0

I'm working with python dictionaries and I want to combine it. The dicts are like below,

devices = [{'EUI':123,'Name':'gum 1'},{'EUI':456,'Name':'gum 2'},{'EUI':789,'Name':'gum 3'}]
data = [{'EUI':123,'data':111},{'EUI':456,'data':222},{'EUI':789,'data':333},{'EUI':456,'data':444},{'EUI':789,'data':555}]

They have in common the EUI (an identifier). What I'm doing is using a pair of loops and check if the EUI is the same or not. If is the same, I combine both dicts.

The final result is,

[{'EUI': 123, 'data': 111, 'Name': 'gum 1'}, {'EUI': 456, 'data': 222, 'Name': 'gum 2'}, {'EUI': 789, 'data': 333, 'Name': 'gum 3'}, {'EUI': 456, 'data': 444, 'Name': 'gum 2'}, {'EUI': 789, 'data': 555, 'Name': 'gum 3'}]

My full code is the following,

devices = [{'EUI':123,'Name':'gum 1'},{'EUI':456,'Name':'gum 2'},{'EUI':789,'Name':'gum 3'}]
data = [{'EUI':123,'data':111},{'EUI':456,'data':222},{'EUI':789,'data':333},{'EUI':456,'data':444},{'EUI':789,'data':555}]

print(data)

for da in data:
  for dev in devices:
    if dev['EUI'] == da['EUI']:
      da.update(dev)
      break

print(data)

Actually it works perfectly, but I think it could a better/easier/pythonic option to do the same. Somebody knows another way to do it?

Thank you very much!

Lleims
  • 1,275
  • 12
  • 39

3 Answers3

1

Since the EUI seems to be unique within the two lists of data you could use a dictionary right away, that maps EUI to other data:

devices = {d.pop('EUI'): d for d in devices}
data = {d.pop('EUI'): d for d in data}

And then you can merge on EUI keys:

for k, d in data.items():
    d.update(devices.get(k, {}))
a_guest
  • 34,165
  • 12
  • 64
  • 118
0

I considered case of len(set(d['EUI'] for d in devices) ^ set(d['EUI'] for d in data)) > 0.
This method preserves original devices and data.

devices = [{'EUI': 123, 'Name': 'gum 1'}, {'EUI': 456, 'Name': 'gum 2'},
           {'EUI': 789, 'Name': 'gum 3'}]
data = [{'EUI': 123, 'data': 111}, {'EUI': 456, 'data': 222},
        {'EUI': 789, 'data': 333}]

device_dict = {
    device['EUI']: device
    for device in devices
}
results = [
    {**device_dict.pop(datum['EUI'], {}), **datum} for datum in data
] + list(device_dict.values())
print(results)

output:

[{'EUI': 123, 'Name': 'gum 1', 'data': 111}, {'EUI': 456, 'Name': 'gum 2', 'data': 222}, {'EUI': 789, 'Name': 'gum 3', 'data': 333}]

explanation:

  • device_dict = {...}: Making EUI keyed dictionary about devices.
  • [{**device_dict[datum['EUI']], **datum} for datum in data]: Merging datum dictionary and device dictionary while looping data
  • **device_dict.pop(datum['EUI'], {}) instead of **device_dict[datum['EUI']]: Considering if datum['EUI'] not in device_dict. Also pop from handled EUIs.
  • + list(device_dict.values()): Appending for rest of device_dict(dictionaries that are only in devices)

corner case data:

devices = [{'EUI': 123, 'Name': 'gum 1'}, {'EUI': 456, 'Name': 'gum 2'},
           {'EUI': 789, 'Name': 'gum 3'}, {'EUI': 888, 'Name': 'gum 4'}]
data = [{'EUI': 123, 'data': 111}, {'EUI': 456, 'data': 222},
        {'EUI': 789, 'data': 333}, {'EUI': 777, 'data': 444}]

output:

[{'EUI': 123, 'Name': 'gum 1', 'data': 111}, {'EUI': 456, 'Name': 'gum 2', 'data': 222}, {'EUI': 789, 'Name': 'gum 3', 'data': 333}, {'EUI': 777, 'data': 444}, {'EUI': 888, 'Name': 'gum 4'}]
Boseong Choi
  • 2,566
  • 9
  • 22
0

from itertools import zip_longest

result = [{**u, **v} for u, v in zip_longest(data, devices, fillvalue={})] print(result)

vks2106
  • 316
  • 4
  • 16