clearScreen clearScreen - 3 months ago 8
Python Question

Merge two lists and create a new dictionary

I could not find a good way to do this. Suppose I have two lists (the lists have objects with given attributes). I need to create a new dictionary/list with merged atttributes.

listA = [
{
"alpha": "some value",
"time": "datetime",
},
...
]

listB = [
{
"beta": "some val",
"gamma": "some val",
"time": "datetime"
},
...
]


The result should be as follows (it should be merged based on "time" attribute)

result = {
"datetime": {
"alpha": "some value",
"beta": "some val",
"gamma": "some val"
},
...
}


How do I do this in a python way?

For example,

listA = [
{
"time": "Jan 1",
"alpha": "one"
},
{
"time": "Jan 3",
"alpha": "three"
}
]

listB = [
{
"beta": "one-one",
"gamma": "one-two",
"time": "Jan 1"
},
{
"beta": "two-one",
"gamma": "two-two",
"time": "Jan 2"
},
]

result = {
"Jan 1": {
"alpha": "one",
"beta": "one-one",
"gamma": "one-two",
},
"Jan 2": {
"beta": "two-one",
"gamma": "two-two",
},
"Jan 3": {
"alpha": "three"
}
}

Answer

Using a list comprehensions

Since you are searching for an alternative not using a for loop here is an implementation using list comprehensions, which results in a two liner. I am not sure though that this is more intuitive than a for loop:

output = {}
[output.setdefault(item["time"],{}).update({key: value}) 
 for key, value in item.items()     
 if key != "time" 
 for item in (listA + listB)]

To me this is just a more convoluted way of for loops... Documentation for setdefault.

Using classic for loops

Use listA and listB as given in your example:

combined = listA + listB

merged = {}
for item in combined:
    time = item["time"]
    # setdefault only acts if the key is not found, initiate a dict then
    merged.setdefault(time, {})
    for key, value in item.items():
        if key != "time":
            merged[time].update({key: value})

print merged

Output:

{'Jan 2': {'beta': 'two-one', 'gamma': 'two-two'}, 'Jan 3': {'alpha': 'three'}, 'Jan 1': {'alpha': 'one', 'beta': 'one-one', 'gamma': 'one-two'}}
Comments