Duplicate python dict for each value - python

In a list containing dictionaries, how do I split it based on unique values of dictionaries? So for instance, this:
t = [
{'name': 'xyz', 'value': ['K','L', 'M', 'N']},
{'name': 'abc', 'value': ['O', 'P', 'K']}
]
becomes this:
t = [
{'name': 'xyz', 'value': 'K'},
{'name': 'xyz', 'value': 'L'},
{'name': 'xyz', 'value': 'M'},
{'name': 'xyz', 'value': 'N'},
{'name': 'abc', 'value': 'O'},
{'name': 'xyz', 'value': 'P'},
{'name': 'xyz', 'value': 'K'}
]

You can do this with a list comprehension. Iterate through each dictionary d, and create a new dictionary for each value in d['values']:
>>> t = [ dict(name=d['name'], value=v) for d in t for v in d['value'] ]
>>> t
[{'name': 'xyz', 'value': 'K'},
{'name': 'xyz', 'value': 'L'},
{'name': 'xyz', 'value': 'M'},
{'name': 'xyz', 'value': 'N'},
{'name': 'abc', 'value': 'O'},
{'name': 'abc', 'value': 'P'},
{'name': 'abc', 'value': 'K'}]

Related

Convert a duplicated list into a combined one with same key

I have a list: and this list could be very long duplicated of the values can vary because of it.
l1 = [[{'node': 'node-3', 'value': 7.5456592756413645},{'node': 'node-5', 'value': 6.988051860579239},{'node': 'node-0', 'value': 11.394453190010722},{'node': 'node-7', 'value': 7.905077155911794}, {'node': 'node-4', 'value': 7.792379308708253}, {'node': 'node-14', 'value': 10.292450756795946}, {'node': 'node-1', 'value': 6.355755419836891}, {'node': 'node-15', 'value': 14.111596406948182}, {'node': 'node-16', 'value': 13.40657800705202}, {'node': 'node-2', 'value': 6.015374411354142}, {'node': 'node-9', 'value': 7.047300820373079}, {'node': 'node-17', 'value': 12.68578754440751}, {'node': 'node-8', 'value': 7.800883809244761}, {'node': 'node-10', 'value': 12.064107712975112}, {'node': 'node-6', 'value': 9.7540013919274}, {'node': 'node-12', 'value': 12.318039154397544}, {'node': 'node-13', 'value': 9.755403652626981}, {'node': 'node-11', 'value': 12.261621612054046}], [{'node': 'node-3', 'value': 6.761078690857657}, {'node': 'node-5', 'value': 8.749145084411227}, {'node': 'node-0', 'value': 12.366653629672784}, {'node': 'node-7', 'value': 9.646920894631135}, {'node': 'node-4', 'value': 6.496804630916606}, {'node': 'node-14', 'value': 13.52834341167122}, {'node': 'node-1', 'value': 6.624804810314409}, {'node': 'node-15', 'value': 16.68569380522415}, {'node': 'node-16', 'value': 15.114235217020076}, {'node': 'node-2', 'value': 6.957799674666696}, {'node': 'node-9', 'value': 11.003732393553822}, {'node': 'node-17', 'value': 14.872999031713572}, {'node': 'node-8', 'value': 6.1783864922581175}, {'node': 'node-10', 'value': 8.761628593039768}, {'node': 'node-6', 'value': 7.151000108866281}, {'node': 'node-12', 'value': 11.369187124409983}, {'node': 'node-13', 'value': 11.13383409022003}, {'node': 'node-11', 'value': 10.450195830323363}]]
As you can see, it is several nested lists with same key, but different values, I need to combined into one nested list, something like:
[
{'node': 'node-3', 'value': [ 7.5456592756413645 , 6.761078690857657, ...]},
{'node': 'node-5', 'value': [ 6.988051860579239 , 8.749145084411227, ... ]}
....
]
You may achieve this, with varying length N of values, with the following:
l2 = [{'nodes': l1[0][i]['node'], 'value': [l1[n][i]['value'] for n in range(len(l1))]} for i in range(len(l1[0]))]
Something to note, the original post requested for 'value'. This was maintained to meet the original request, but I would encourage you to use a generalized name like 'all_attributes' or 'all_values' instead due to the variable length. This will eliminate future confusion if the 'value' contains more than a single value or 'values' containing to a single value. However, just be sure to document what you decide.
Results:
[
{'nodes': 'node-3', 'value': [7.5456592756413645, 6.761078690857657]}
{'nodes': 'node-5', 'value': [6.988051860579239, 8.749145084411227]}
{'nodes': 'node-0', 'value': [11.394453190010722, 12.366653629672784]}
{'nodes': 'node-7', 'value': [7.905077155911794, 9.646920894631135]}
{'nodes': 'node-4', 'value': [7.792379308708253, 6.496804630916606]}
{'nodes': 'node-14', 'value': [10.292450756795946, 13.52834341167122]}
{'nodes': 'node-1', 'value': [6.355755419836891, 6.624804810314409]}
{'nodes': 'node-15', 'value': [14.111596406948182, 16.68569380522415]}
{'nodes': 'node-16', 'value': [13.40657800705202, 15.114235217020076]}
{'nodes': 'node-2', 'value': [6.015374411354142, 6.957799674666696]}
{'nodes': 'node-9', 'value': [7.047300820373079, 11.003732393553822]}
{'nodes': 'node-17', 'value': [12.68578754440751, 14.872999031713572]}
{'nodes': 'node-8', 'value': [7.800883809244761, 6.1783864922581175]}
{'nodes': 'node-10', 'value': [12.064107712975112, 8.761628593039768]}
{'nodes': 'node-6', 'value': [9.7540013919274, 7.151000108866281]}
{'nodes': 'node-12', 'value': [12.318039154397544, 11.369187124409983]}
{'nodes': 'node-13', 'value': [9.755403652626981, 11.13383409022003]}
{'nodes': 'node-11', 'value': [12.261621612054046, 10.450195830323363]}
]
You can do it with zip
[{'node': i.get('node'), 'values': [j.get('value') for v in j]} for i,j in zip(*l1)]
For the use zip in both sublists, the order should be equal.
Output:
[{'node': 'node-3', 'values': [6.761078690857657, 6.761078690857657]},
{'node': 'node-5', 'values': [8.749145084411227, 8.749145084411227]},
{'node': 'node-0', 'values': [12.366653629672784, 12.366653629672784]},
{'node': 'node-7', 'values': [9.646920894631135, 9.646920894631135]},
{'node': 'node-4', 'values': [6.496804630916606, 6.496804630916606]},
{'node': 'node-14', 'values': [13.52834341167122, 13.52834341167122]},
{'node': 'node-1', 'values': [6.624804810314409, 6.624804810314409]},
{'node': 'node-15', 'values': [16.68569380522415, 16.68569380522415]},
{'node': 'node-16', 'values': [15.114235217020076, 15.114235217020076]},
{'node': 'node-2', 'values': [6.957799674666696, 6.957799674666696]},
{'node': 'node-9', 'values': [11.003732393553822, 11.003732393553822]},
{'node': 'node-17', 'values': [14.872999031713572, 14.872999031713572]},
{'node': 'node-8', 'values': [6.1783864922581175, 6.1783864922581175]},
{'node': 'node-10', 'values': [8.761628593039768, 8.761628593039768]},
{'node': 'node-6', 'values': [7.151000108866281, 7.151000108866281]},
{'node': 'node-12', 'values': [11.369187124409983, 11.369187124409983]},
{'node': 'node-13', 'values': [11.13383409022003, 11.13383409022003]},
{'node': 'node-11', 'values': [10.450195830323363, 10.45019583032

Filter list of dictionaries by nested attributes

I have the current list I'd like to filter by type=orange:
my_list = [{'anotherfieds': 'aaa',
'fruits': [{'tastes': 'good', 'type': 'orange'},
{'tastes': 'bad', 'type': 'apple'}],
'name': 'A'},
{'differentfield': 'bbb',
'fruits': [{'tastes': 'so-so', 'type': 'orange'},
{'tastes': 'good', 'type': 'banana'}],
'name': 'B'},
{'fruits': [{'tastes': 'good', 'type': 'avocado'},
{'tastes': 'yes', 'type': 'lemon'}],
'name': 'C',
'somethingelse': 'ccc'}]
As an output I'd like to have all dictionaries that have type equal to orange in their attributes, so output is expected like following:
[{'anotherfieds': 'aaa',
'fruits': [{'tastes': 'good', 'type': 'orange'},
{'tastes': 'bad', 'type': 'apple'}],
'name': 'A'},
{'differentfield': 'bbb',
'fruits': [{'tastes': 'so-so', 'type': 'orange'},
{'tastes': 'good', 'type': 'banana'}],
'name': 'B'}]
All the dictionaries always contain list of dictionaries that contain type.
The most far I got is this:
jmespath.search('[].fruits[?type==`orange`] []', my_list)
>>> [{'tastes': 'good', 'type': 'orange'}, {'tastes': 'so-so', 'type': 'orange'}]
But I need the whole list elements, like above, not only sub-elements.
How can I filter the list for entire elements having this specific key-value pair?
See JMESPath documentation: Filter Expressions.
The filter-expression should be:
[?fruits[?type==`orange`]]
to filter al elements of the array or list that have fruits with desired type:
import jmespath
my_list = [{'anotherfieds': 'aaa',
'fruits': [{'tastes': 'good', 'type': 'orange'},
{'tastes': 'bad', 'type': 'apple'}],
'name': 'A'},
{'differentfield': 'bbb',
'fruits': [{'tastes': 'so-so', 'type': 'orange'},
{'tastes': 'good', 'type': 'banana'}],
'name': 'B'},
{'fruits': [{'tastes': 'good', 'type': 'avocado'},
{'tastes': 'yes', 'type': 'lemon'}],
'name': 'C',
'somethingelse': 'ccc'}]
elements_with_oranges = jmespath.search('[?fruits[?type==`orange`]]', my_list)
print(elements_with_oranges)
Prints desired 2 of the 3:
[{'anotherfieds': 'aaa', 'fruits': [{'tastes': 'good', 'type': 'orange'}, {'tastes': 'bad', 'type': 'apple'}], 'name': 'A'}, {'differentfield': 'bbb', 'fruits': [{'tastes': 'so-so', 'type': 'orange'}, {'tastes': 'good', 'type': 'banana'}], 'name': 'B'}]

merger two list of dictionaries with common key

I have 2 list of dictionaries:-
x = [{'Name': 'SG', 'State': 'All good'}, {'Name': 'AA', 'State': 'All good'}]
y = [{'Name': 'SG', 'Alias': 'blue', 'Status': 'Started'},
{'Name': 'AA', 'Alias': 'blue', 'Status': 'Started'}]
Would like to merge them both with y showing as:
y = [{'Name': 'SG', 'Alias': 'blue', 'Status': 'Started', 'State: 'All good'},
{'Name': 'AA', 'Alias': 'blue', 'Status': 'Started', 'State: 'All good'}]
Below code does not give the desired result:
for i in range(len(x)):
for k, v in x[i]:
y[i][k] = v
NOte: x and y both the list have the same number of dictionaries and both have a matching "Name"
Here's a simpler way that does the same as what I think you're trying to do in your code:
>>> for d1, d2 in zip(x, y):
... d2.update(d1)
...
>>> y
[{'Name': 'SG', 'Alias': 'blue', 'Status': 'Started', 'State': 'All good'}, {'Name': 'AA', 'Alias': 'blue', 'Status': 'Started', 'State': 'All good'}]
If the dictionnaries are perfectly matching by pairs, look #Iguananaut solution
If not, and you have to check the Name field, I'd suggest you build intermediate dict {Name:value}, then you iterate to retrieve the possible informations in both, that allow to have missing values (missing Name) in any of the dict
x = [{'Name': 'SG', 'State': 'All good'}, {'Name': 'AA', 'State': 'All good'}]
y = [{'Name': 'SG', 'Alias': 'blue', 'Status': 'Started'},
{'Name': 'AA', 'Alias': 'blue', 'Status': 'Started'}]
prepare_x = {row['Name']: row for row in x}
prepare_y = {row['Name']: row for row in y}
result = [{**prepare_x.get(key, {}), **prepare_y.get(key, {})}
for key in (prepare_x.keys() | prepare_y.keys())]

Remove duplicates from list of dictionaries within list of dictionaries

I have list:
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'a'},
{'name': 'b'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'},
{'name': 'a'}]}]
I want to remove duplicates from the list of dictionaries in 'account':
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'}]}]
When using set, I get the following error:
TypeError: unhashable type: 'dict'
Can anybody help me with this problem?
This structure is probably over complicated, but it gets the job done.
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'a'},
{'name': 'b'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'},
{'name': 'a'}]}]
>>> [{'date': date,
'account': [{'name': name} for name in group]
} for group, date in zip([set(account.get('name')
for account in item.get('account'))
for item in my_list],
[d.get('date') for d in my_list])]
[{'account': [{'name': 'a'}, {'name': 'b'}], 'date': '10.06.2016'},
{'account': [{'name': 'a'}], 'date': '22.06.2016'}]
def deduplicate_account_names(l):
for d in l:
names = set(map(lambda d: d.get('name'), d['account']))
d['account'] = [{'name': name} for name in names]
# even shorter:
# def deduplicate_account_names(l):
# for d in l:
# d['account'] = [{'name': name} for name in set(map(lambda d: d.get('name'), d['account']))]
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'a'},
{'name': 'b'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'},
{'name': 'a'}]}]
deduplicate_account_names(my_list)
print(my_list)
# [ {'date': '10.06.2016',
# 'account': [ {'name': 'a'},
# {'name': 'b'} ] },
# {'date': '22.06.2016',
# 'account': [ {'name': 'a'} ] } ]
Sets can only have hashable members and neither lists nor dicts are - but they can be checked for equality.
you can do
def without_duplicates(inlist):
outlist=[]
for e in inlist:
if e not in outlist:
outlist.append(e)
return outlist
this can be slow for really big lists
Give this code a try:
for d in my_list:
for k in d:
if k == 'account':
v = []
for d2 in d[k]:
if d2 not in v:
v.append(d2)
d[k] = v
This is what you get after running the snippet above:
In [347]: my_list
Out[347]:
[{'account': [{'name': 'a'}, {'name': 'b'}], 'date': '10.06.2016'},
{'account': [{'name': 'a'}], 'date': '22.06.2016'}]

How to use list comprehensions to make a dict having list of list as values

I Have a list as following and I want to convert that as output shown below using List comprehensions. Any help is appreciated.
a = [{'type': 'abc', 'values': 1},
{'type': 'abc', 'values': 2},
{'type': 'abc', 'values': 3},
{'type': 'xyz', 'values': 4},
{'type': 'xyz', 'values': 5},
{'type': 'pqr', 'values': 6},
{'type': 'pqr', 'values': 8},
{'type': 'abc', 'values': 9},
{'type': 'mno', 'values': 10},
{'type': 'def', 'values': 11}]
This is the output I am expecting.
output = {'abc': [1,2,3,9], 'xyz': [4,5], 'pqr': [6,8], 'mno': [10], 'def': [11]}
from operator import itemgetter
from itertools import groupby
a = [{'type': 'abc', 'values': 1},
{'type': 'abc', 'values': 2},
{'type': 'abc', 'values': 3},
{'type': 'xyz', 'values': 4},
{'type': 'xyz', 'values': 5},
{'type': 'pqr', 'values': 6},
{'type': 'pqr', 'values': 8},
{'type': 'abc', 'values': 9},
{'type': 'mno', 'values': 10},
{'type': 'def', 'values': 11}]
typegetter = itemgetter('type')
valuesgetter = itemgetter('values')
groups = groupby(sorted(a, key=typegetter), key=typegetter)
print {k:list(map(valuesgetter, v)) for k, v in groups}
a = [{'type': 'abc', 'values': 1},
{'type': 'abc', 'values': 2},
{'type': 'abc', 'values': 3},
{'type': 'xyz', 'values': 4},
{'type': 'xyz', 'values': 5},
{'type': 'pqr', 'values': 6},
{'type': 'pqr', 'values': 8},
{'type': 'abc', 'values': 9},
{'type': 'mno', 'values': 10},
{'type': 'def', 'values': 11}]
output = {}
for item in a:
output[item['type']] = [item['values']] if output.get(item['type'], None) is None else output[item['type']] + [item['values']]
print output

Categories