combine two python lists of dict with index - python

I want to merge two lists into a nested construct.
List_A: [{'id':1,'val':'abc'},{'id':2,'val':'bcd'},{'id':3,'val':'efg'}]
List_B: [{'ref':1,'name':'xyz'},{'ref':2,'name':'opq'},{'ref:2,'name':'jkl'},{'ref':3,'name':'nmo'}]
Result should be:
List_C: [{'id':1,'list_b':[{'name':'xyz'}]},{'id':2,'list_b':[{'name':'opq'},{'name':'jkl'}]},{'id':3,'list_b':[{'name':'nmo'}]}]
I tried pandas join and merge but got no result. Sure, I could iterate through the list and do it key by key, but there might be a much better solution.

Based on your desired output, you don't need List_A at all.
from collections import defaultdict
b = [{'ref':1,'name':'xyz'}, {'ref':2,'name':'opq'}, {'ref':2,'name':'jkl'},{'ref':3,'name':'nmo'}]
dct = {}
[dct.setdefault(tuple(i), list()).append(j) for *i, j in [tuple(x.values()) for x in b]]
[{'id':k[0], 'list_b':list({'name': n} for n in v)} for k, v in dct.items()]
Output:
[{'id': 1, 'list_b': [{'name': 'xyz'}]},
{'id': 2, 'list_b': [{'name': 'opq'}, {'name': 'jkl'}]},
{'id': 3, 'list_b': [{'name': 'nmo'}]}]
Overall this seems like an over-complicated way to store the data, but if you need that specific format (ex for an input to another program) then w/e.

from copy import deepcopy
List_C = deepcopy(List_A)
for dct1 in List_C:
dct1.pop('val')
dct1['list_b'] = list()
for dct2 in List_B:
if dct1['id'] == dct2['ref']:
dct3 = dct2.copy()
dct3.pop('ref')
dct1['list_b'].append(dct3)

Related

Custom sort list of dictionaries by other dictionary or list

I have a list of dictionaries that I would like to order based on an external ordering (list, dictionary, whatever works). Let's say I have the following list:
list_a = [{"dylan": "alice"}, {"arnie": "charles"}, {"chelsea": "bob"}]
and I want to sort it like this
sorted_list_a = [{"arnie": "charles"}, {"chelsea": "bob"}, {"dylan": "alice"}]
I've tried to do it like this:
# list_a will have a variable number of dictionaries all with unique keys
# list_order will have all dictionary keys ordered, even if they don't appear in list_a
list_order = [{"arnie": 1}, {"britta": 2}, {"chelsea": 3}, {"dylan": 4}]
list_a.sort(key=lambda x: list_order[x.keys()])
but I get TypeError: list indices must be integers or slices, not dict_keys. I feel like I'm close, but I can't quite get to the end.
Try this:
def fun(x):
k, = (x)
for d in list_order:
if k in d:
return d[k]
res = sorted(list_a, key=fun)
print(res)
Output:
[{'arnie': 'charles'}, {'chelsea': 'bob'}, {'dylan': 'alice'}]
l = [{"dylan": "alice"}, {"arnie": "charles"}, {"chelsea": "bob"}]
d={}
for i in l:
for x,y in (i.items()):
d[x]=y
print(sorted(d.items(),key=lambda x: x[0]))

compare a list with values in dictionary

I have a dictionary contains lists of values and a list:
dict1={'first':['hi','nice'], 'second':['night','moon']}
list1= [ 'nice','moon','hi']
I want to compare the value in the dictionary with the list1 and make a counter for the keys if the value of each key appeared in the list:
the output should like this:
first 2
second 1
here is my code:
count = 0
for list_item in list1:
for dict_v in dict1.values():
if list_item.split() == dict_v:
count+= 1
print(dict.keys,count)
any help? Thanks in advance
I would make a set out of list1 for the O(1) lookup time and access to the intersection method. Then employ a dict comprehension.
>>> dict1={'first':['hi','nice'], 'second':['night','moon']}
>>> list1= [ 'nice','moon','hi']
>>>
>>> set1 = set(list1)
>>> {k:len(set1.intersection(v)) for k, v in dict1.items()}
{'first': 2, 'second': 1}
intersection accepts any iterable argument, so creating sets from the values of dict1 is not necessary.
You can use the following dict comprehension:
{k: sum(1 for i in l if i in list1) for k, l in dict1.items()}
Given your sample input, this returns:
{'first': 2, 'second': 1}
You can get the intersection of your list and the values of dict1 using sets:
for key in dict1.keys():
count = len(set(dict1[key]) & set(list1))
print("{0}: {1}".format(key,count))
While brevity can be great, I thought it would be good to also provide an example that is as close to the OPs original code as possible:
# notice conversion to set for O(1) lookup
# instead of O(n) lookup where n is the size of the list of desired items
dict1={'first':['hi','nice'], 'second':['night','moon']}
set1= set([ 'nice','moon','hi'])
for key, values in dict1.items():
counter = 0
for val in values:
if val in set1:
counter += 1
print key, counter
Using collections.Counter
from collections import Counter
c = Counter(k for k in dict1 for i in list1 if i in dict1[k])
# Counter({'first': 2, 'second': 1})
The most simplest and basic approach would be:
dict1={'first':['hi','nice'], 'second':['night','moon']}
list1= [ 'nice','moon','hi']
listkeys=list(dict1.keys())
listvalues=list(dict1.values())
for i in range(0,len(listvalues)):
ctr=0
for j in range(0,len(listvalues[i])):
for k in range(0,len(list1)):
if list1[k]==listvalues[i][j]:
ctr+=1
print(listkeys[i],ctr)
Hope it helps.

Transform list of dictionaries into dict of dicts

What is the easiest way to transform this list of dictionaries:
[
{'code': 1, name:'A', value:'1'},
{'code': 1, name:'B', value:'2'},
{'code': 2, name:'C', value:'3'},
{'code': 2, name:'D', value:'4'},
{'code': 3, name:'E', value:'5'},
{'code': 3, name:'F', value:'6'},
......
]
into this:
{
1: [{name:'A', value:'1'}, {name:'B', value:'2'}],
2: [{name:'C', value:'3'}, {name:'D', value:'4'}],
3: [{name:'E', value:'5'}, {name:'F', value:'6'}],
...
}
I would like a nice solution like list comprehension, not the hard way.
Thanks
A list comprehension would require an (inefficient) sorting operation, then grouping.
It's much easier to use a dictionary and a loop:
res = {}
for entry in inputlist:
code = entry.pop('code')
res.setdefault(code, []).append(entry)
This alters the original dictionaries; create a copy first if this is an issue:
entry = dict(entry)
code = entry.pop('code')
If your input list is already sorted, then you could use itertools.groupby() to produce the dictionary in a one-liner, but the readability of this solution is debatable:
from itertools import groupby
from operator import itemgetter
res = {key: [{k: v for k, v in d.items() if k != 'code'} for d in group]
for key, group in groupby(inputlist, itemgetter('code'))}

Python 2.7 - Sum value on duplicates in dictionary

I have a list of dictionaries like:
list1=[{'a':'apples', 'b':'snack','count':2},{'a':'apples','b':'lunch','count':3},{'a':'apples','b':'snack','count':3}]
I need to group duplicates in the list on 'a' and 'b' and sum their 'count' such that:
list2=[{'a':'apples','b':'snack','count':5},{'a':'apples','b':'lunch','count':3}]
Searched through the repository here and haven't recognized a solution. Thanks very much for any pointers.
You can use a defaultdict with a 2tuple to accumulate the counts, then push it back to a list...
list1=[{'a':'apples', 'b':'snack','count':2},{'a':'apples','b':'lunch','count':3},{'a':'apples','b':'snack','count':3}]
from collections import defaultdict
dd = defaultdict(int)
for d in list1:
dd[d['a'], d['b']] += d['count']
list2 = [{'a': k[0], 'b': k[1], 'count': v} for k, v in dd.iteritems()]
[{'a': 'apples', 'count': 3, 'b': 'lunch'}, {'a': 'apples', 'count': 5, 'b': 'snack'}]
Another solution, using groupby and list,dict and generator comprehensions:
list1=[{'a':'apples', 'b':'snack','count':2},{'a':'apples','b':'lunch','count':3},{'a':'apples','b':'snack','count':3}]
from itertools import groupby
list1.sort()
group_func = lambda x: {key:val for key, val in x.iteritems() if key!='count'}
list2 = [dict(k, count = sum(item['count'] for item in items)) for k, items in groupby(list1, group_func)]
[{'a': 'apples', 'count': 3, 'b': 'lunch'}, {'a': 'apples', 'count': 5, 'b': 'snack'}]
Explanation:
The grouper function takes an item and return a sub-dictionary
without the 'count' item using dict-comprehension.
Then groupby gathers all original list items with the same subdict
Finally the list comprehension iterates those groups and sums (now using generator comprehension) the count items.
Cons:
Less readable.
For groupby to work it needs to be sorted, so that could make things slower.
Pros:
If list1 is already sorted this is probably faster. (since comprehensions are generally faster in python)
Shorter. (can even be written in a single barely comprehensible line :))

Python dictionary manipulation

I got a list of object
lst = [1,2,3]
I want them in a dictionary with a default key 'number', and then put them in a list.
The result should look like
lst = [{'number':1},{'number':2},{'number':3}
Use less code, please.
Use a list comprehension
lst = [{'number': x} for x in lst]
This matches your code samples:
>>> lst = [1,2,3]
>>> newlst = [dict(number=n) for n in lst]
>>> newlst
[{'number': 1}, {'number': 2}, {'number': 3}]
>>>
What you say, however, is a bit different - you want them all in the same dictionary, or each in a dictionary of its own? The snippet above gives you the latter.

Categories