Can't process list of dicts against list of strings - python

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]

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

Merge and Sum Dictionaries

a = {'A':{'x':1,'y':0,'z':0}, 'B':{'x':0,'y':0,'z':0}}
b = {'A':{'x':0,'y':1,'z':0}, 'B':{'x':0,'y':0,'z':0}}
Given above dictionaries, how can I sum those values and merge into one single dictionary as below?
{'A':{'x':1,'y':1,'z':0}, 'B':{'x':0,'y':0,'z':0}}
You can use pandas:
>>> import pandas as pd
>>> a = {'A':{'x':1,'y':0,'z':0}, 'B':{'x':0,'y':0,'z':0}}
>>> b = {'A':{'x':0,'y':1,'z':0}, 'B':{'x':0,'y':0,'z':0}}
>>> (pd.DataFrame(a) + pd.DataFrame(b)).to_dict()
{'A': {'x': 1, 'y': 1, 'z': 0}, 'B': {'x': 0, 'y': 0, 'z': 0}}
This is applicable for posted example only.
For more general idea, where you have only 1s and 0s to work with:
>>> a = {'A':{'x':1,'y':1,'z':0}, 'B':{'x':0,'y':0,'z':0}}
>>> b = {'A':{'x':0,'y':1,'z':0}, 'B':{'x':0,'y':0,'z':0}}
>>> (pd.DataFrame(a) + pd.DataFrame(b)).astype(bool).replace({True:1, False:0})
A B
x 1 0
y 1 0
z 0 0
>>> (pd.DataFrame(a) + pd.DataFrame(b)).astype(bool).replace({True:1, False:0}).to_dict()
{'A': {'x': 1, 'y': 1, 'z': 0}, 'B': {'x': 0, 'y': 0, 'z': 0}}
Or
>>> (pd.DataFrame(a) | pd.DataFrame(b)).to_dict()
{'A': {'x': 1, 'y': 1, 'z': 0}, 'B': {'x': 0, 'y': 0, 'z': 0}}
For something without importing a library:
>>> {out_k:{k:(a[out_k][k] or b[out_k][k]) for k in a[out_k]} for out_k in a}
{'A': {'x': 1, 'y': 1, 'z': 0}, 'B': {'x': 0, 'y': 0, 'z': 0}}
Using collections.defaultdict and Counter:
from collections import defaultdict, Counter
d = defaultdict(Counter)
for dic in [a,b]:
for k, v in dic.items():
d[k].update(v)
Output:
defaultdict(collections.Counter,
{'A': Counter({'x': 1, 'y': 1, 'z': 0}),
'B': Counter({'x': 0, 'y': 0, 'z': 0})})
Add this code:
c = {}
c['A'] = a['A'].update(b['A'])
c['B'] = a['B'].update(b['B'])

Is there a pythonic way to iterate a dictionary of ranges to build new dictionaries?

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}]

Flatten dictionary of dictionaries

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'}]
>>>

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)

Categories