Python combine values of identical dictionaries without using looping - python

I have list of identical dictionaries:
my_list = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}]
I need to get something like this:
a = [1, 4, 7]
b = [2, 5, 8]
c = [3, 6, 9]
I know how to do in using for .. in .., but is there way to do it without looping?
If i do
a, b, c = zip(*my_list)
i`m getting
a = ('a', 'a', 'a')
b = ('b', 'b', 'b')
c = ('c', 'c', 'c')
Any solution?

You need to extract all the values in my_list.You could try:
my_list = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}]
a, b, c = zip(*map(lambda d: d.values(), my_list))
print(a, b, c)
# (1, 4, 7) (2, 5, 8) (3, 6, 9)
Pointed out by #Alexandre,This work only when the dict is ordered.If you couldn't make sure the order, consider the answer of yatu.

You will have to loop to obtain the values from the inner dictionaries. Probably the most appropriate structure would be to have a dictionary, mapping the actual letter and a list of values. Assigning to different variables is usually not the best idea, as it will only work with the fixed amount of variables.
You can iterate over the inner dictionaries, and append to a defaultdict as:
from collections import defaultdict
out = defaultdict(list)
for d in my_list:
for k,v in d.items():
out[k].append(v)
print(out)
#defaultdict(list, {'a': [1, 4, 7], 'b': [2, 5, 8], 'c': [3, 6, 9]})

Pandas DataFrame has just a factory method for this, so if you already have it as a dependency or if the input data is large enough:
import pandas as pd
my_list = ...
df = pd.DataFrame.from_rows(my_list)
a = list(df['a']) # df['a'] is a pandas Series, essentially a wrapped C array
b = list(df['b'])
c = list(df['c'])

Please find the code below. I believe that the version with a loop is much easier to read.
my_list = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}]
# we assume that all dictionaries have the sames keys
a, b, c = map(list, map(lambda k: map(lambda d: d[k], my_list), my_list[0]))
print(a,b,c)

Related

Are there formal names for these list/dict data structures

My code is working fine, but I made up a couple names for how I'm handling data in lists and dicts. I'm not sure if they are intuitive; they're just what popped in my head at the time.
Are there accepted names already in use? (If you have a made-up name that's better than mine, fine, but I'm really looking for generally accepted names if they exist.)
Specifically:
datalist: a list of lists with headers in [0] followed by rows
datamap: a list of dicts with name: value for every item
headers = ['a', 'b', 'c']
rows = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
datalist = [['a', 'b', 'c'], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
datamap = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}]
I think the closest thing to what you're describing is a type hint. It's an unambiguous way to specify the type of a data structure, as well as the types that the data structure holds. These type hints are ignored at runtime, but they help readers of your code understand what each data structure contains and can be used with libraries such as mypy to detect typing errors:
from typing import Union, TypedDict
class DataEntry(TypedDict):
a: int
b: int
c: int
DataMap = list[DataEntry]
headers: list[str] = ['a', 'b', 'c']
rows: list[list[int]] = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
datalist: list[Union[list[str], list[int]]] = [['a', 'b', 'c'], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
datamap: DataMap = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}]

How to read a tuple of dict keys

Say I have a a dictionary (e.g. d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}).
Say I want to read several keys of the dictionary, but not all (e.g. I want to read d['a'] and d['c']).
Here is the way I do it: (val_a, val_c) = (d[key] for key in ('a', 'c')).
Is there a more pythonic way to do this?
Use operator.itemgetter.
>>> from operator import itemgetter
>>> d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> get_ac = itemgetter('a', 'c')
>>> get_ac(d)
(1, 3)
Very similar to yours, but slightly shorter using map.
(Note: Just as with your approach, the result of map is not actually a tuple but a generator that is unpacked into multiple variables.)
>>> d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> a, c = map(d.get, ('a', 'c'))
>>> a, c
(1, 3)

Restructuring the hierarchy of dictionaries in Python?

If I have a nested dictionary in Python, is there any way to restructure it based on keys?
I'm bad at explaining, so I'll give a little example.
d = {'A':{'a':[1,2,3],'b':[3,4,5],'c':[6,7,8]},
'B':{'a':[7,8,9],'b':[4,3,2],'d':[0,0,0]}}
Re-organize like this
newd = {'a':{'A':[1,2,3],'B':[7,8,9]},
'b':{'A':[3,4,5],'B':[4,3,2]},
'c':{'A':[6,7,8]},
'd':{'B':[0,0,0]}}
Given some function with inputs like
def mysteryfunc(olddict,newkeyorder):
????
mysteryfunc(d,[1,0])
Where the [1,0] list passed means to put the dictionaries 2nd level of keys in the first level and the first level in the 2nd level. Obviously the values need to be associated with their unique key values.
Edit:
Looking for an answer that covers the general case, with arbitrary unknown nested dictionary depth.
Input:
d = {'A':{'a':[1,2,3],'b':[3,4,5],'c':[6,7,8]},
'B':{'a':[7,8,9],'b':[4,3,2],'d':[0,0,0]}}
inner_dict={}
for k,v in d.items():
print(k)
for ka,va in v.items():
val_list=[]
if ka not in inner_dict:
val_dict={}
val_dict[k]=va
inner_dict[ka]=val_dict
else:
val_dict=inner_dict[ka]
val_dict[k]=va
inner_dict[ka]=val_dict
Output:
{'a': {'A': [1, 2, 3], 'B': [7, 8, 9]},
'b': {'A': [3, 4, 5], 'B': [4, 3, 2]},
'c': {'A': [6, 7, 8]},
'd': {'B': [0, 0, 0]}}
you can use 2 for loops, one to iterate over each key, value pair and the second for loop to iterate over the nested dict, at each step form the second for loop iteration you can build your desired output:
from collections import defaultdict
new_dict = defaultdict(dict)
for k0, v0 in d.items():
for k1, v1 in v0.items():
new_dict[k1][k0] = v1
print(dict(new_dict))
output:
{'a': {'A': [1, 2, 3], 'B': [7, 8, 9]},
'b': {'A': [3, 4, 5], 'B': [4, 3, 2]},
'c': {'A': [6, 7, 8]},
'd': {'B': [0, 0, 0]}}
You can use recursion with a generator to handle input of arbitrary depth:
def paths(d, c = []):
for a, b in d.items():
yield from ([((c+[a])[::-1], b)] if not isinstance(b, dict) else paths(b, c+[a]))
from collections import defaultdict
def group(d):
_d = defaultdict(list)
for [a, *b], c in d:
_d[a].append([b, c])
return {a:b[-1][-1] if not b[0][0] else group(b) for a, b in _d.items()}
print(group(list(paths(d))))
Output:
{'a': {'A': [1, 2, 3], 'B': [7, 8, 9]}, 'b': {'A': [3, 4, 5], 'B': [4, 3, 2]}, 'c': {'A': [6, 7, 8]}, 'd': {'B': [0, 0, 0]}}

subtracting all values in dictionaries were values are list of floats

I have two dictionaries where each value is a list of floats
d1 = {'a': [10,11,12], 'b': [9,10,11], 'c': [8,9,10], 'd': [7,8,9]}
d2 = {'a': [1,1,1], 'b': [2,3,2], 'c': [1,2,2], 'd': [4,3,4]}
I want to subtract the values between dictionaries d1-d2 and get the result:
d3 = {'a': [9,10,11], 'b': [7,7,9], 'c': [7,7,9], 'd': [3,5,5] }
I have found on this site entries on how to subtract dictionaries with only one float value per key, and how to subtract lists within each dictionary, but not between dictionaries.
Also, speed needs to be taken into account because I am going to run this ~200,000 times with different dictionaries each time.
Use a dict comprehension with
zip:
>>> {k:[x-y for x, y in zip(d1[k], d2[k])] for k in d1}
{'a': [9, 10, 11], 'c': [7, 7, 8], 'b': [7, 7, 9], 'd': [3, 5, 5]}
or map:
>>> from operator import sub
>>> {k:map(sub, d1[k], d2[k]) for k in d1}
{'a': [9, 10, 11], 'c': [7, 7, 8], 'b': [7, 7, 9], 'd': [3, 5, 5]}
If speed is important then you can try numpy:
import numpy as np
def sub(x, y):
# probably it would be better if x and y already had numpy arrays as the values.
return {key: np.array(x[key]) - np.array(y[key]) for key in x}
print sub(d1, d2)

How to subtract values from dictionaries

I have two dictionaries in Python:
d1 = {'a': 10, 'b': 9, 'c': 8, 'd': 7}
d2 = {'a': 1, 'b': 2, 'c': 3, 'e': 2}
I want to substract values between dictionaries d1-d2 and get the result:
d3 = {'a': 9, 'b': 7, 'c': 5, 'd': 7 }
Now I'm using two loops but this solution is not too fast
for x,i in enumerate(d2.keys()):
for y,j in enumerate(d1.keys()):
I think a very Pythonic way would be using dict comprehension:
d3 = {key: d1[key] - d2.get(key, 0) for key in d1}
Note that this only works in Python 2.7+ or 3.
Use collections.Counter, iif all resulting values are known to be strictly positive. The syntax is very easy:
>>> from collections import Counter
>>> d1 = Counter({'a': 10, 'b': 9, 'c': 8, 'd': 7})
>>> d2 = Counter({'a': 1, 'b': 2, 'c': 3, 'e': 2})
>>> d3 = d1 - d2
>>> print d3
Counter({'a': 9, 'b': 7, 'd': 7, 'c': 5})
Mind, if not all values are known to remain strictly positive:
elements with values that become zero will be omitted in the result
elements with values that become negative will be missing, or replaced with wrong values. E.g., print(d2-d1) can yield Counter({'e': 2}).
Just an update to Haidro answer.
Recommended to use subtract method instead of "-".
d1.subtract(d2)
When - is used, only positive counters are updated into dictionary.
See examples below
c = Counter(a=4, b=2, c=0, d=-2)
d = Counter(a=1, b=2, c=3, d=4)
a = c-d
print(a) # --> Counter({'a': 3})
c.subtract(d)
print(c) # --> Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
Please note the dictionary is updated when subtract method is used.
And finally use dict(c) to get Dictionary from Counter object
Haidro posted an easy solution, but even without collections you only need one loop:
d1 = {'a': 10, 'b': 9, 'c': 8, 'd': 7}
d2 = {'a': 1, 'b': 2, 'c': 3, 'e': 2}
d3 = {}
for k, v in d1.items():
d3[k] = v - d2.get(k, 0) # returns value if k exists in d2, otherwise 0
print(d3) # {'c': 5, 'b': 7, 'a': 9, 'd': 7}

Categories

Resources