# Optimising two for loops in Python

I would like to make this code more efficient, I have isolated the problem as being these two for loops:

    for i, device in enumerate(list_devices):
for data_type_attr_name in data_types:
result_list_element = {
"device_reference": device.name,
"device_name": "REF - " + device.name,
"data_type": data_type_attr_name,
"type": next(
(data_type["type"] for data_type in DATA_TYPES if data_type["name"] == data_type_attr_name)
),
"data_points": getattr(device, data_type_attr_name)(
is_last_value=is_last_value,
from_timestamp=from_timestamp,
to_timestamp=to_timestamp,
aggregate_period_name=aggregate_period_name,
aggregate_operation_name=aggregate_operation_name,
decimal_places=decimal_places,
),
}
if not isinstance(result_list_element["data_points"], list):
raise TypeError("data_points must be returned as a list, even if it contains only one element.")
result_list.append(result_list_element)

return result_list


list_devices is a list of Django model objects, data_types is a list of strings, each one representing a data type.

Is there any way of losing one of the for loops while maintaining the same output?

Thanks

import itertools

for device, data_type_attr_name in itertools.product(list_devices, data_types):
result_list_element = {
"device_reference": device.name,
"device_name": "REF - " + device.name,
"data_type": data_type_attr_name,
"type": next((data_type["type"] for data_type in DATA_TYPES if data_type["name"] == data_type_attr_name)),
"data_points": getattr(device, data_type_attr_name)(
is_last_value=is_last_value,
from_timestamp=from_timestamp,
to_timestamp=to_timestamp,
aggregate_period_name=aggregate_period_name,
aggregate_operation_name=aggregate_operation_name,
decimal_places=decimal_places,
),
}
if not isinstance(result_list_element["data_points"], list):
raise TypeError("data_points must be returned as a list, even if it contains only one element.")
result_list.append(result_list_element)
return result_list


Assume you are referring to speed, not conciseness when asking about efficiency. In which case reducing the amount of loops will not necessarily improve performance.

"type": next((data_type["type"] for data_type in DATA_TYPES if data_type["name"] == data_type_attr_name))


This can be improved so that you are not needing to go over DATA_TYPES looking for a matching name to data_type_attr_name every iteration. Instead you can make a reverse lookup dictionary once before the loop where data_type["name"] is the key.

Whenever you are searching through a list often, it can be very beneficial to create a dictionary.