Problems to create a nested Python dictonary - python

I try to create a dictonary with Python 3. Here is my code:
data = {}
data['price'] = []
data['place1'] = []
data['place2'] = []
data['place1'].append({
'x': 2,
'y': 1
})
data['place2'].append({
'a': 5,
'b': 6
})
data['price'].append(data['place1'])
data['price'].append(data['place2'])
print(data)
so the output ist:
{'price': [[{'x': 2, 'y': 1}], [{'a': 5, 'b': 6}]], 'place1': [{'x': 2, 'y': 1}], 'place2': [{'a': 5, 'b': 6}]}
But I need it like in this example:
'price'
->'place1'
->'x'=2
->'y'=1
->'place2'
->'a'=5
->'b'=6
Is diconary the correct method for this?
Thanks for your help!
Best, Marius

Well, you're appending lists here: data['price'].append(data['place1']), so now data['price'] is a list of lists.
You can write a simple dictionary literal instead:
data = {
'price': {
'place1': {
'x': 2,
'y': 1
},
'place2': {
'a': 5,
'b': 6
}
}
}
Or, if you insist on appending data dynamically:
data = {'price': {}}
data['price']['place1'] = {'x': 2, 'y': 1}
data['price']['place2'] = {'a': 5, 'b': b}

Just to keep the original content as much as possible, you need to make data['price'] a dict then put place1 and place2 inside it.
data = {}
data['price'] = {}
data['price']['place1'] = []
data['price']['place2'] = []
data['price']['place1'].append({
'x': 2,
'y': 1
})
data['price']['place2'].append({
'a': 5,
'b': 6
})

No, you cannot map the (:) on the dictionary to an (=) sign as your output.

Related

is there any way in python to create list using key value pairs

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

How to combine two list containing dictionary with similar keys?

Assuming that there are two python list with the same structure like this:
var1 = [{'a':1,'b':2},{'c':2,'d':5,'h':4},{'c':2,'d':5,'e':4}]
var2 = [{'a':3,'b':2},{'c':1,'d':5,'h':4},{'c':5,'d':5,'e':4}]
In my case, i need to combine both of those list, so i'll get this value :
result = [{'a':4,'b':4},{'c':3,'d':10,'h':8},{'c':7,'d':10,'e':8}]
How can i do that?
zip-based one-liner comprehension:
result = [{k: d1[k]+d2[k] for k in d1} for d1, d2 in zip(var1, var2)]
This assumes that two dicts at the same index always have identical key sets.
Use list comprehensions to put the code in one line,
result = [{key : d1.get(key, 0)+d2.get(key, 0)
for key in set(d1.keys()) | set(d2.keys())} # union two sets
for d1, d2 in zip(var1, var2)]
print(result)
[{'a': 4, 'b': 4}, {'h': 8, 'c': 3, 'd': 10}, {'c': 7, 'e': 8, 'd': 10}]
This code takes into consideration the case that two dictionaries may not have the same keys.
var1 = [{'a':1,'b':2},{'c':2,'d':5,'h':4},{'c':2,'d':5,'e':4}]
var2 = [{'a':3,'b':2},{'c':1,'d':5,'h':4},{'c':5,'d':5,'e':4}]
res = []
for i in range(len(var1)):
dic = {}
dic1, dic2 = var1[i], var2[i]
for key, val in dic1.items(): // dic1.iteritems() in python 2.
dic[key] = dic1[key] + dic2[key]
res.append(dic)
>>>print(res)
[{'a': 4, 'b': 4}, {'c': 3, 'd': 10, 'h': 8}, {'c': 7, 'd': 10, 'e': 8}]
var1 = [{'a': 1, 'b': 2}, {'c': 2, 'd': 5, 'h': 4}, {'c': 2, 'd': 5, 'e': 4}]
var2 = [{'a': 3, 'b': 2}, {'c': 1, 'd': 5, 'h': 4}, {'c': 5, 'd': 5, 'e': 4}]
ret = []
for i, ele in enumerate(var1):
d = {}
for k, v in ele.items():
value = v
value += var2[i][k]
d[k] = value
ret.append(d)
print(ret)
For the sake of completeness, another zip-based one-liner that will work even if the dicts are uneven in the both lists:
result = [{k: d1.get(k, 0) + d2.get(k, 0) for k in set(d1) | set(d2)} for d1, d2 in zip(var1, var2)]
Would something like this help?
ar1 = [{'a':1,'b':2},{'c':2,'d':5,'h':4},{'c':2,'d':5,'e':4}]
var2 = [{'a':3,'b':2},{'c':1,'d':5,'h':4},{'c':5,'d':5,'e':4}]
combined_var = zip(var1, var2)
new_d = {}
list_new_ds = []
for i, j in combined_var:
new_d = {}
for key in i and j:
new_d[key] = i[key] + j[key]
list_new_ds.append(new_d)
list_new_ds = [{'a': 4, 'b': 4}, {'h': 8, 'c': 3, 'd': 10}, {'c': 7, 'e': 8, 'd': 10}]
To explain, the zip function merges the lists as a list of tuples. I then unpack the tuples and iterate through the keys in each dictionary and add the values for the same keys together using a new dictionary to store them. I then append the value to a list, and then re-initialise the temporary dictionary to empty before looking at the next tuple in the zipped list.
The order is different due to dictionary behaviour I believe.
I am a novice, so would appreciate any critiques of my answer!

Nested dictionary with lists to many dictionaries

I have nested dictionary with lists like this
{
'a': 1,
'x':[
{'b': 1,
'c': [
{'z': 12},
{'z': 22},
]
},
{'b': 2,
'c': [
{'z': 10},
{'z': 33},
]
}
]
}
And I want to convert it to list of flat dictionaries i form like this.
[
{'a': 1, 'b': 1, 'z': 12},
{'a': 1, 'b': 1, 'z': 22},
{'a': 1, 'b': 2, 'z': 10},
{'a': 1, 'b': 2, 'z': 33},
]
Any idea how to achieve that?
The following produces the requested result:
[{'a': 1, 'b': 1, 'z': 12}, {'a': 1, 'b': 2, 'z': 10}]
Use at your own risk. The following was only tested on your example.
from itertools import product
def flatten(D):
if not isinstance(D, dict): return D
base = [(k, v) for k, v in D.items() if not isinstance(v, list)]
lists = [[flatten(x) for x in v] for k, v in D.items() if isinstance(v, list)]
l = []
for p in product(*lists):
r = dict(base)
for a in p:
for d in a:
r.update(d)
l.append(r)
return l
The following tests above.
d = {
'a': 1,
'x':[
{'b': 1,
'c': [
{'z': 12}
]
},
{'b': 2,
'c': [
{'z': 10}
]
}
]
}
print flatten(d)
A possible solution is:
#!/usr/bin/env python3
d = {
'a': 1,
'x': [
{
'b': 1,
'c': [
{'z': 12}
]
},
{
'b': 2,
'c': [
{'z': 10}
]
}
]
}
res = [{"a": 1, "b": x["b"], "z": x["c"][0]["z"]} for x in d["x"]]
print(res)
This assumes that there is only one a (with a fixed value of 1) and x element and this element is added to the comprehension manually.
The other two elements (b and z) are taken from x array with a list comprehension.
To learn more about how comprehensions work read the following:
Python Documentation - 5.1.4. List Comprehensions
Python: List Comprehensions
PS. You are supposed to first show what you have tried so far and get help on that. Take a look at SO rules before posting your next question.

Update list of dictionaries elementwise in Python

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)

how to uniqify a list of dict in python

I have a list:
d = [{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':2}]
{'x':1, 'y':2} comes more than once I want to remove it from the list.My result should be:
d = [{'x':1, 'y':2}, {'x':3, 'y':4} ]
Note:
list(set(d)) is not working here throwing an error.
If your value is hashable this will work:
>>> [dict(y) for y in set(tuple(x.items()) for x in d)]
[{'y': 4, 'x': 3}, {'y': 2, 'x': 1}]
EDIT:
I tried it with no duplicates and it seemed to work fine
>>> d = [{'x':1, 'y':2}, {'x':3, 'y':4}]
>>> [dict(y) for y in set(tuple(x.items()) for x in d)]
[{'y': 4, 'x': 3}, {'y': 2, 'x': 1}]
and
>>> d = [{'x':1,'y':2}]
>>> [dict(y) for y in set(tuple(x.items()) for x in d)]
[{'y': 2, 'x': 1}]
Dicts aren't hashable, so you can't put them in a set. A relatively efficient approach would be turning the (key, value) pairs into a tuple and hashing those tuples (feel free to eliminate the intermediate variables):
tuples = tuple(set(d.iteritems()) for d in dicts)
unique = set(tuples)
return [dict(pairs) for pairs in unique]
If the values aren't always hashable, this is not possible at all using sets and you'll propably have to use the O(n^2) approach using an in check per element.
Avoid this whole problem and use namedtuples instead
from collections import namedtuple
Point = namedtuple('Point','x y'.split())
better_d = [Point(1,2), Point(3,4), Point(1,2)]
print set(better_d)
A simple loop:
tmp=[]
for i in d:
if i not in tmp:
tmp.append(i)
tmp
[{'x': 1, 'y': 2}, {'x': 3, 'y': 4}]
tuple the dict won't be okay, if the value of one dict item looks like a list.
e.g.,
data = [
{'a': 1, 'b': 2},
{'a': 1, 'b': 2},
{'a': 2, 'b': 3}
]
using [dict(y) for y in set(tuple(x.items()) for x in data)] will get the unique data.
However, same action on such data will be failed:
data = [
{'a': 1, 'b': 2, 'c': [1,2]},
{'a': 1, 'b': 2, 'c': [1,2]},
{'a': 2, 'b': 3, 'c': [3]}
]
ignore the performance, json dumps/loads could be a nice choice.
data = set([json.dumps(d) for d in data])
data = [json.loads(d) for d in data]
Another dark magic(please don't beat me):
map(dict, set(map(lambda x: tuple(x.items()), d)))

Categories