How can I flatten a dictionary of dictonaries in Python, and put them into a list? For example, say I have the following dict:
data = { id1 : {x: 1, y: 2, z: 3}, id2 : {x: 4, y: 5, z: 6}}
How do I get:
[{id: id1, x: 1, y: 2, z: 3}, {id: id2, x: 4, y: 5, z: 6}]
With python 3.5 and higher
>>> data = { 'id1' : {'x': 1, 'y': 2, 'z': 3}, 'id2' : {'x': 4, 'y': 5, 'z': 6}}
>>> [{**v, 'id':k} for k,v in data.items()]
[{'x': 1, 'y': 2, 'z': 3, 'id': 'id1'}, {'x': 4, 'y': 5, 'z': 6, 'id': 'id2'}]
On older python versions
>>> [dict(v, id=k) for k,v in data.iteritems()]
[{'x': 1, 'y': 2, 'z': 3, 'id': 'id1'}, {'x': 4, 'y': 5, 'z': 6, 'id': 'id2'}]
>>>
Related
how to create a list of key value pairs in python???
I have these two lists:
x = [1,2,3,4,5]
y = [11,12,13,14,15]
I have tried this code:
l = {i:{'x': x[i], 'y': y[i]} for i in range(len(x))}
print(l)
output I am getting:
{0: {'x': 1, 'y': 11}, 1: {'x': 2, 'y': 12}, 2: {'x': 3, 'y': 13}, 3: {'x': 4, 'y': 14}, 4: {'x': 5, 'y': 15}}
expected output:
[0: {'x': 1, 'y': 11}, 1: {'x': 2, 'y': 12}, 2: {'x': 3, 'y': 13}, 3: {'x': 4, 'y': 14}, 4: {'x': 5, 'y': 15}]
Maybe you need this
x = [1,2,3,4,5]
y = [11,12,13,14,15]
l = [{i:{'x': x[i], 'y': y[i]}}for i in range(len(x))]
print(l)
The closest you can get to the expected output is an array which contains dictionaries it would look like this.
x = [1,2,3,4,5]
y = [11,12,13,14,15]
array = []
for i in len(x):
array.append({'x' : x[i], 'y' : y[i]})
Output will be:
[{'x': 1, 'y': 11}, {'x': 2, 'y': 12}]
You can access an element like this:
array[0]['x'] = 1
array[1]['y'] = 12
Supposing that a have this dict with the keys and some range:
d = {"x": (0, 2), "y": (2, 4)}
I need to create dicts using the range above, I will get:
>>> keys = [k for k,v in d.items()]
>>>
>>> def newDict(keys,array):
... return dict(zip(keys,array))
...
>>> for i in range(0,2):
... for j in range(2,4):
... dd = newDict(keys, [i,j])
... print (dd)
...
{'x': 0, 'y': 2}
{'x': 0, 'y': 3}
{'x': 1, 'y': 2}
{'x': 1, 'y': 3}
My doubt is how to iterate change the key using the ranges and create a new dicts in a more pythonic way.
Supposing the I add more one key z:
d = {"x": (0, 2), "y": (2, 4), "z": (3, 5)}
So, I will need to add a more for loop nested. Is there another approach?
Yes, you can replace your nested loops with a single itertools.product call.
>>> from itertools import product
>>> p = product(*([(k, v) for v in range(*V)] for k, V in d.items()))
>>> list(map(dict, p))
[{'x': 0, 'y': 2}, {'x': 0, 'y': 3}, {'x': 1, 'y': 2}, {'x': 1, 'y': 3}]
How it works -
For each key : value pair (e.g., "x": (0, 2)), flatten it to form a list of tuples (e.g., [("x", 0), ("x", 1)]). You get one list for each pair
Take the cartesian product. You get a iterator of lists of tuples
For each iterator, convert the list of tuples to a dictionary using map
Listify the entire result
First, store your ranges directly as range objects, rather than as endpoints:
>>> d = {'x': (0, 2), 'y': (2, 4), 'z': (3, 5)}
>>> d = {k: range(*v) for k, v in d.items()}
Now you have simple list comprehension available:
>>> from itertools import product
>>> [dict(zip(d, p)) for p in product(*d.values())]
[{'x': 0, 'y': 2, 'z': 3},
{'x': 0, 'y': 2, 'z': 4},
{'x': 0, 'y': 3, 'z': 3},
{'x': 0, 'y': 3, 'z': 4},
{'x': 1, 'y': 2, 'z': 3},
{'x': 1, 'y': 2, 'z': 4},
{'x': 1, 'y': 3, 'z': 3},
{'x': 1, 'y': 3, 'z': 4}]
I have a list of dictionaries
[ {'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 3}]
I need to filter out elements who's 'cat' value is present too few times
if I set the minimum number of instances to two, in the list above, the instance containing 'cat': 3 should be filtered out because 'cat':3 is present only once in the list, there are enough instances of 'cat': 1 and 'cat': 2
the output should be
[ {'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2}]
I don't care about the order, I need to keep original dictionaries
You could use collections.Counter to check the frequency of categories and build a set from the ones that are frequent enough:
import collections
source = [{'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 3}]
minimum_count = 2
category_counts = collections.Counter(item['cat'] for item in source)
# category_counts == {1: 4, 2: 3, 3: 1}
frequent_categories = {
category for category, count in category_counts.items()
if count > minimum_count
}
# frequent_categories == {1, 2}
result = [item for item in source if item['cat'] in frequent_categories]
you can try this code:
l = [
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 3}
]
from collections import Counter
def select(l, times):
counters = Counter(map(lambda x : x['cat'], l)).most_common(times)
return filter(lambda item: item['cat'] in dict(counters) , l)
print select(l, 2)
Say we have a list of dictionaries in Python:
A = [{'x': 1, 'y': 2, 'z': 3},{'x': 0, 'y': 10, 'z': 11}]
We pick out the 'x'-values using map()
x = map((lambda i: i['x']), A)
and do something with them. Now, what is the cleanest way to update all the 'x'-values of A in a comparable way - ie., without using a for-loop?
In a single line?
map(lambda (i,v) : A[i].update(v), enumerate(map((lambda i: {'x':i['x'] + 1}), A)))
Where, in this case, you're incrementing the value of X. Although I'd suggest that this isn't the prettiest way to do anything, nor the most readable. At least by doing the update method you're not relying on a 'hidden' internal like setitem, and it's a little more flexible in that you could be doing changes to more than one key at a time.
>>> r = [{'x': 1, 'y': 2, 'z': 3},{'x': 0, 'y': 10, 'z': 11}]
>>> r
[{'y': 2, 'x': 1, 'z': 3}, {'y': 10, 'x': 0, 'z': 11}]
>>> [i.__setitem__('x', 10) for i in r]
[None, None]
>>> r
[{'y': 2, 'x': 10, 'z': 3}, {'y': 10, 'x': 10, 'z': 11}]
It's not horrible, but I think a for loop would be nicer. I'd only do this if 'r' were really large and performance is super important.
>>> map((lambda i: i.__setitem__('x',10)), A)
[None, None]
>>> A
[{'y': 2, 'x': 10, 'z': 3}, {'y': 10, 'x': 10, 'z': 11}]
But this is ugly. And I would use for-loop.
Let X be a list of the updated values for "x":
while X:
A[len(X)]['x'] = X.pop()
If you first extracted all the 'x' values into a list as shown, you could update them like this:
A = [{'x': 1, 'y': 2, 'z': 3},{'x': 0, 'y': 10, 'z': 11}]
x = map((lambda i: i['x']), A)
def do_something(x):
return x+1
print A
# [{'y': 2, 'x': 1, 'z': 3}, {'y': 10, 'x': 0, 'z': 11}]
map((lambda i,v: i.__setitem__('x', do_something(v))), A, x)
print A
# [{'y': 2, 'x': 2, 'z': 3}, {'y': 10, 'x': 1, 'z': 11}]
However the same result could be obtained more efficiently with the following which doesn't need all the 'x' values to first be extracted into a separate list:
map((lambda i: (i.__setitem__('x', do_something(i['x'])))), A)
d = ['X + Y = Z', 'X <=Y']
p = [{'Y': 1, 'X': 0, 'Z': 0}, {'Y': 1, 'X': 0, 'Z': 3}, {'Y': 1, 'X': 0, 'Z': 6}, {'Y': 1, 'X': 0, 'Z': 9}, {'Y': 1, 'X': 1, 'Z': 0}, {'Y': 1, 'X': 1, 'Z': 3}]
I need to create create some structure which would store List of expressions, where variables are changed.
I need to know:
X, Y, Z current values
expressions with changed letters to integers
and it has to be for each dict of values
The problem is to see for what X,Y,Z, all expressions are True
According the expressions are made by you (so you can trust them), a simple solution is to use eval() like this :
correct_values = []
for value in p:
#if eval(d[0], value) and eval(d[1], value): # basic version
if all(eval(exp, value) for exp in d): # ehanced version thanks to #isbadawi
correct_values.append(value)
but you'll have to correct the expression X + Y = Z is not valid python, X + Y == Z is a valid python expression.
But with the values you gave in example, nothing is matching :(
I would've opted for a more secure solution than using eval:
p = [{'Y': 1, 'X': 0, 'Z': 0}, {'Y': 1, 'X': 0, 'Z': 3},
{'Y': 1, 'X': 0, 'Z': 6}, {'Y': 1, 'X': 0, 'Z': 9},
{'Y': 1, 'X': 1, 'Z': 0}, {'Y': 1, 'X': 1, 'Z': 3}]
f = lambda v: all([v['X'] + v['Y'] == v['Z'],
v['X'] <= v['Y'],
2*v['X'] + v['Y'] < v['Z']])
print [f(k) for k in p]
# Output: [False, False, False, False, False, False]