How to transform this dict output? - python

I have a little bit of a logic game. I have list with following dicts in each listnode.
{1: [1,{'X': -0.48595, 'Y': 0.0, 'Z': 0.56283},
2,{'X': -0.48595, 'Y': 0.0, 'Z': -0.6}],
2: [2,{'X': -0.48595, 'Y': 0.0, 'Z': -0.6},
4,{'X': 1.14756, 'Y': 0.0, 'Z': -0.6}],
3: [4,{'X': 1.14756, 'Y': 0.0, 'Z': -0.6},
9,{'X': 1.14756, 'Y': 0.0, 'Z': 0.8}]}
What I want? List with nodes of lists as below:
[{'Id': 1, 'Nodes': [{'Id': 1, 'Position': {'X': -0.48595, 'Y': 0.0, 'Z': 0.56283}},
{'Id': 2, 'Position': {'X': -0.48595, 'Y': 0.0, 'Z': -0.6}}]},
{'Id': 2, 'Nodes': [{'Id': 2, 'Position': {'X': -0.48595, 'Y': 0.0, 'Z': -0.6}},
{'Id': 4, 'Position': {'X': 1.14756, 'Y': 0.0, 'Z': -0.6}}]},
{'Id': 3, 'Nodes': [{'Id': 4, 'Position': {'X': 1.14756, 'Y': 0.0, 'Z': -0.6}},
{'Id': 9, 'Position': {'X': 1.14756, 'Y': 0.0, 'Z': 0.8}}]}]
How can I make that transformation? I'm keep trying modifying my code, but everytime something's wrong.
mem_list = []
for x in range(len(list_temp)):
mem_loc_list = []
for key in list_temp[x]:
nodes_list = []
member = {}
member['Id'] = key
node_dict = {}
for y in list_temp[x][key]:
if type(y) == int:
node_dict['Id'] = y
else:
node_dict['Position'] = y
nodes_list.append(node_dict)
member['Nodes'] = nodes_list
mem_loc_list.append(member)

Using list comprehension you can do it like this:
[[{"Id": k, "Nodes": [{"Id": v[i], "Position": v[i+1]} for i in range(0, len(v), 2)]}
for k,v in data.items()] for data in list_temp]

Related

How to sort dictionary by values in inner dictionary

{1: {'p_place': {'x': 0.65, 'y': 0.255, 'z': 0.279}, 'q_place': {'q0': 1.0, 'q1': 0.0, 'q2': 0.0, 'q3': 0.0}, 'offset_pick': {'x': (0.0,), 'y': (0.0,), 'z': (0.05,)}, 'centroid_upper': {'x': (0.65,), 'y': (0.2549999999999998,), 'z': (0.329,)}}, 2: {'p_place': {'x': 0.65, 'y': 0.255, 'z': 0.279}, 'q_place': {'q0': 1.0, 'q1': 0.0, 'q2': 0.0, 'q3': 0.0}, 'offset_pick': {'x': (0.0,), 'y': (0.0,), 'z': (0.05,)}, 'centroid_upper': {'x': (0.65,), 'y': (0.2549999999999998,), 'z': (0.329,)}}}
I have this kind of dictionary. I want to sort it by value Y and Z of p_place
Did you try anything at all?
newd = sorted(dct, key=lambda el: (el['p_place']['y'],el['p_place']['z']))

Permutation of items with quantities

Using python I have to get all the permutations of given subset using python.
I used itertools.permutation but result is a bit different.
Think of a machine and it has a maximum capacity, and we have products can be produced together, and we have to fill the capacity of machine.
Output format is not important, I used a dictionary to describe it. I will make a calculation after getting this combinations.
For example :
products = {'x','y','z','a'}
machine_capcacity = 8
#required output as follows:
{'x':5,'y':1,'z':1,'a':1}
{'x':4,'y':2,'z':1,'a':1}
{'x':4,'y':1,'z':2,'a':1}
{'x':4,'y':1,'z':1,'a':2}
{'x':3,'y':3,'z':1,'a':1}
{'x':3,'y':1,'z':3,'a':1}
{'x':3,'y':1,'z':1,'a':3}
{'x':3,'y':2,'z':2,'a':1}
{'x':3,'y':2,'z':1,'a':2}
{'x':3,'y':1,'z':2,'a':2}
{'x':2,'y':4,'z':1,'a':1}
# ...
{'x':6,'y':1,'z':1} # This can't be in results,since need at least 1 element of product
{'x':4,'y':1,'z':1,'a':1} # This can't be in results,since we need to fill the capacity
And we dont want repeating elements:
{'x':5,'y':1,'z':1,'a':1}
and
{'a':1,'y':1,'z':1,'x':5}
is same thing for us.
Here is a solution not relying on itertools since it's getting contrived with all the constraints (a product yielding unique results and a minimum of 1 appearance per product):
products = {'x','y','z','a'}
machine_capacity=8
def genCap(capacity = machine_capacity,used = 0):
if used == len(products)-1: yield capacity,None
else:
for i in range(1,2+capacity-len(products)+used):
yield i,genCap(capacity-i,used+1)
def printCaps(caps,current = []):
if caps is None:
print(dict(zip(products,current)))
return
for i in caps:
printCaps(i[1],current+[i[0]])
printCaps(genCap())
might be optimize-able with tail recursion and the like. Looks almost like groupby, but I can't see an easy way to use that.
For posterity I leave my old solution - product repeats counts, so filtering it becomes a problem of it's own:
You confused product with permutation. Here is a quick solution using itertools product, and the Counter collection to create the output you want:
from collections import Counter
from itertools import product
products = {'x','y','z','a'}
machine_capacity=8
for x in filter(lambda x: len(x) == len(products),
map(Counter,product(products,repeat=machine_capacity))):
print(dict(x))
Note both product and map are lazy, so they won't be evaluated until you need them. Counter provides the output you want, and converting to dict cleans it up. Note no order is guaranteed anywhere. The filter is used to make sure all your products appear at least once (length of counter equals that of products) - and it is also lazy, so only evaluated when you need it.
You can use a recursive function to find all possible combinations of the values in range(machine_capacity) that both sum to 8 and are unique. Then, the elements in products can be mapped to each element in the sublists of the combinations found:
products = ['x','y','z','a']
machine_capacity = 8
def combinations(d, current = []):
if len(current) == len(products):
yield current
else:
for i in range(machine_capacity):
if sum(current+[i]) <= machine_capacity:
yield from combinations(d, current+[i])
data = [dict(zip(products, i)) for i in filter(lambda x:sum(x) == 8 and len(x) == len(set(x)), combinations(machine_capacity))]
Output:
[{'a': 5, 'x': 0, 'z': 2, 'y': 1}, {'a': 4, 'x': 0, 'z': 3, 'y': 1}, {'a': 3, 'x': 0, 'z': 4, 'y': 1}, {'a': 2, 'x': 0, 'z': 5, 'y': 1}, {'a': 5, 'x': 0, 'z': 1, 'y': 2}, {'a': 1, 'x': 0, 'z': 5, 'y': 2}, {'a': 4, 'x': 0, 'z': 1, 'y': 3}, {'a': 1, 'x': 0, 'z': 4, 'y': 3}, {'a': 3, 'x': 0, 'z': 1, 'y': 4}, {'a': 1, 'x': 0, 'z': 3, 'y': 4}, {'a': 2, 'x': 0, 'z': 1, 'y': 5}, {'a': 1, 'x': 0, 'z': 2, 'y': 5}, {'a': 5, 'x': 1, 'z': 2, 'y': 0}, {'a': 4, 'x': 1, 'z': 3, 'y': 0}, {'a': 3, 'x': 1, 'z': 4, 'y': 0}, {'a': 2, 'x': 1, 'z': 5, 'y': 0}, {'a': 5, 'x': 1, 'z': 0, 'y': 2}, {'a': 0, 'x': 1, 'z': 5, 'y': 2}, {'a': 4, 'x': 1, 'z': 0, 'y': 3}, {'a': 0, 'x': 1, 'z': 4, 'y': 3}, {'a': 3, 'x': 1, 'z': 0, 'y': 4}, {'a': 0, 'x': 1, 'z': 3, 'y': 4}, {'a': 2, 'x': 1, 'z': 0, 'y': 5}, {'a': 0, 'x': 1, 'z': 2, 'y': 5}, {'a': 5, 'x': 2, 'z': 1, 'y': 0}, {'a': 1, 'x': 2, 'z': 5, 'y': 0}, {'a': 5, 'x': 2, 'z': 0, 'y': 1}, {'a': 0, 'x': 2, 'z': 5, 'y': 1}, {'a': 1, 'x': 2, 'z': 0, 'y': 5}, {'a': 0, 'x': 2, 'z': 1, 'y': 5}, {'a': 4, 'x': 3, 'z': 1, 'y': 0}, {'a': 1, 'x': 3, 'z': 4, 'y': 0}, {'a': 4, 'x': 3, 'z': 0, 'y': 1}, {'a': 0, 'x': 3, 'z': 4, 'y': 1}, {'a': 1, 'x': 3, 'z': 0, 'y': 4}, {'a': 0, 'x': 3, 'z': 1, 'y': 4}, {'a': 3, 'x': 4, 'z': 1, 'y': 0}, {'a': 1, 'x': 4, 'z': 3, 'y': 0}, {'a': 3, 'x': 4, 'z': 0, 'y': 1}, {'a': 0, 'x': 4, 'z': 3, 'y': 1}, {'a': 1, 'x': 4, 'z': 0, 'y': 3}, {'a': 0, 'x': 4, 'z': 1, 'y': 3}, {'a': 2, 'x': 5, 'z': 1, 'y': 0}, {'a': 1, 'x': 5, 'z': 2, 'y': 0}, {'a': 2, 'x': 5, 'z': 0, 'y': 1}, {'a': 0, 'x': 5, 'z': 2, 'y': 1}, {'a': 1, 'x': 5, 'z': 0, 'y': 2}, {'a': 0, 'x': 5, 'z': 1, 'y': 2}]

Permuting a order of items in a list in python

I have a list of dictionary items
[{'x': 0, 'y': 0}, {'x': 1, 'y': 0}, {'x': 2, 'y': 2}]
I want to have an array of "array of dictionaries" with all the maximum permutation order of the list for example for the above array it would be (3 factorial ways)
[[{'x': 0, 'y': 0}, {'x': 1, 'y': 0}, {'x': 2, 'y': 2}],
[{'x': 0, 'y': 0}, {'x': 2, 'y': 2}, {'x': 1, 'y': 0}],
[{'x': 1, 'y': 0}, {'x': 0, 'y': 0}, {'x': 2, 'y': 2}],
[{'x': 1, 'y': 0}, {'x': 2, 'y': 2}, {'x': 0, 'y': 0}],
[{'x': 2, 'y': 2}, {'x': 1, 'y': 0}, {'x': 0, 'y': 0}],
[{'x': 2, 'y': 2}, {'x': 0, 'y': 0}, {'x': 1, 'y': 0}]]
itertools can do permutations
#!python2
import itertools
yourlist = [{'x': 0, 'y': 0}, {'x': 1, 'y': 0}, {'x': 2, 'y': 2}]
for seq in itertools.permutations(yourlist):
print seq
'''
({'y': 0, 'x': 0}, {'y': 0, 'x': 1}, {'y': 2, 'x': 2})
({'y': 0, 'x': 0}, {'y': 2, 'x': 2}, {'y': 0, 'x': 1})
({'y': 0, 'x': 1}, {'y': 0, 'x': 0}, {'y': 2, 'x': 2})
({'y': 0, 'x': 1}, {'y': 2, 'x': 2}, {'y': 0, 'x': 0})
({'y': 2, 'x': 2}, {'y': 0, 'x': 0}, {'y': 0, 'x': 1})
({'y': 2, 'x': 2}, {'y': 0, 'x': 1}, {'y': 0, 'x': 0})
'''
Despite the comments, if you are still messed with how to solve your issue, consider the following.
Strategy: Make use of permutations from itertoolswhich returns a list of tuples in this case. Then, iterating through to convert list of tuples to list of lists to match with your required output.
Here is how you could do:
>>> import itertools
>>> lst = [{'x': 0, 'y': 0}, {'x': 1, 'y': 0}, {'x': 2, 'y': 2}]
>>> [list(elem) for elem in list(itertools.permutations(lst))]
[[{'x': 0, 'y': 0}, {'x': 1, 'y': 0}, {'x': 2, 'y': 2}],
[{'x': 0, 'y': 0}, {'x': 2, 'y': 2}, {'x': 1, 'y': 0}],
[{'x': 1, 'y': 0}, {'x': 0, 'y': 0}, {'x': 2, 'y': 2}],
[{'x': 1, 'y': 0}, {'x': 2, 'y': 2}, {'x': 0, 'y': 0}],
[{'x': 2, 'y': 2}, {'x': 0, 'y': 0}, {'x': 1, 'y': 0}],
[{'x': 2, 'y': 2}, {'x': 1, 'y': 0}, {'x': 0, 'y': 0}]]

Counting matching dictionaries

I have a list containing dictionaries:
[{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb4340', 'y': u'osgb4000'},
{'x': u'osgb4020', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'}]
I wish to count the incidents of each dict and create a new field count
The desired outcome looks like this:
[{'x': u'osgb32', 'y': u'osgb4000', 'count': 3},
{'x': u'osgb4340', 'y': u'osgb4000', 'count': 1},
{'x': u'osgb4020', 'y': u'osgb4000', 'count': 1}]
I am unsure how to match dicts.
This is a job for collections.Counter. But first you have to convert your dicts to actual tuples, as dicts are not hashable and thus can not be used as keys in a Counter object:
>>> dicts = [{'x': u'osgb32', 'y': u'osgb4000'},
... {'x': u'osgb4340', 'y': u'osgb4000'},
... {'x': u'osgb4020', 'y': u'osgb4000'},
... {'x': u'osgb32', 'y': u'osgb4000'},
... {'x': u'osgb32', 'y': u'osgb4000'}]
>>> collections.Counter(tuple(d.items()) for d in dicts)
Counter({(('y', u'osgb4000'), ('x', u'osgb32')): 3,
(('y', u'osgb4000'), ('x', u'osgb4020')): 1,
(('y', u'osgb4000'), ('x', u'osgb4340')): 1})
Then, you can turn those back into dicts with the added "count" key:
>>> c = collections.Counter(tuple(d.items()) for d in dicts)
>>> [dict(list(k) + [("count", c[k])]) for k in c]
[{'count': 1, 'x': u'osgb4020', 'y': u'osgb4000'},
{'count': 3, 'x': u'osgb32', 'y': u'osgb4000'},
{'count': 1, 'x': u'osgb4340', 'y': u'osgb4000'}]
You can use Counter and frozenset for this:
from collections import Counter
l = [{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb4340', 'y': u'osgb4000'},
{'x': u'osgb4020', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'}]
c = Counter(frozenset(d.items()) for d in l)
[dict(k, count=v) for k, v in c.items()] # [{'y': u'osgb4000', 'x': u'osgb4340', 'count': 1}, {'y': u'osgb4000', 'x': u'osgb32', 'count': 3}, {'y': u'osgb4000', 'x': u'osgb4020', 'count': 1}]
You can achieve that easily with code below
items = [{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb4340', 'y': u'osgb4000'},
{'x': u'osgb4020', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'}]
result = {}
counted_items = []
for item in items:
key = item['x'] + '_' + item['y']
result[key] = result.get(key, 0) + 1
for key, value in result.iteritems():
y, x = key.split('_')
counted_items.append({'x': x, 'y': y, 'count': value})
print counted_items # [{'y': u'osgb32', 'x': u'osgb4000', 'count': 3}, {'y': u'osgb4340', 'x': u'osgb4000', 'count': 1}, {'y': u'osgb4020', 'x': u'osgb4000', 'count': 1}]
Another option is to use counter. There are plenty of answers of how to dial with collections.Counter :)
Good Luck!
You can pass your list of dicts as the data arg to DataFrame ctor:
In [74]:
import pandas as pd
data = [{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb4340', 'y': u'osgb4000'},
{'x': u'osgb4020', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'},
{'x': u'osgb32', 'y': u'osgb4000'}]
df = pd.DataFrame(data)
df
Out[74]:
x y
0 osgb32 osgb4000
1 osgb4340 osgb4000
2 osgb4020 osgb4000
3 osgb32 osgb4000
4 osgb32 osgb4000
you can then groubpy on the cols and call size to get a count:
In [76]:
df.groupby(['x','y']).size()
Out[76]:
x y
osgb32 osgb4000 3
osgb4020 osgb4000 1
osgb4340 osgb4000 1
dtype: int64
and then call to_dict:
In [77]:
df.groupby(['x','y']).size().to_dict()
Out[77]:
{('osgb32', 'osgb4000'): 3,
('osgb4020', 'osgb4000'): 1,
('osgb4340', 'osgb4000'): 1}
You can wrap the above into a list:
In [79]:
[df.groupby(['x','y']).size().to_dict()]
Out[79]:
[{('osgb32', 'osgb4000'): 3,
('osgb4020', 'osgb4000'): 1,
('osgb4340', 'osgb4000'): 1}]
You can reset_index, rename the column and pass arg orient='records':
In [94]:
df.groupby(['x','y']).size().reset_index().rename(columns={0:'count'}).to_dict(orient='records')
Out[94]:
[{'count': 3, 'x': 'osgb32', 'y': 'osgb4000'},
{'count': 1, 'x': 'osgb4020', 'y': 'osgb4000'},
{'count': 1, 'x': 'osgb4340', 'y': 'osgb4000'}]

Select highest value from python list of dicts

In a list of list of dicts:
A = [
[{'x': 1, 'y': 0}, {'x': 2, 'y': 3}, {'x': 3, 'y': 4}, {'x': 4, 'y': 7}],
[{'x': 1, 'y': 0}, {'x': 2, 'y': 2}, {'x': 3, 'y': 13}, {'x': 4, 'y': 0}],
[{'x': 1, 'y': 20}, {'x': 2, 'y': 4}, {'x': 3, 'y': 0}, {'x': 4, 'y': 8}]
]
I need to retrieve the highest 'y' values from each of the list of dicts...so the resulting list would contain:
Z = [(4, 7), (3,13), (1,20)]
In A, the 'x' is the key of each dict while 'y' is the value of each dict.
Any ideas? Thank you.
max accept optional key parameter.
A = [
[{'x': 1, 'y': 0}, {'x': 2, 'y': 3}, {'x': 3, 'y': 4}, {'x': 4, 'y': 7}],
[{'x': 1, 'y': 0}, {'x': 2, 'y': 2}, {'x': 3, 'y': 13}, {'x': 4, 'y': 0}],
[{'x': 1, 'y': 20}, {'x': 2, 'y': 4}, {'x': 3, 'y': 0}, {'x': 4, 'y': 8}]
]
Z = []
for a in A:
d = max(a, key=lambda d: d['y'])
Z.append((d['x'], d['y']))
print Z
UPDATE
suggested by – J.F. Sebastian:
from operator import itemgetter
Z = [itemgetter(*'xy')(max(lst, key=itemgetter('y'))) for lst in A]
I'd use itemgetter and max's key argument:
from operator import itemgetter
pair_getter = itemgetter('x', 'y')
[pair_getter(max(d, key=itemgetter('y'))) for d in A]
[max(((d['x'], d['y']) for d in l), key=lambda t: t[1]) for l in A]
The solution to your stated problem has been given, but I suggest changing your underlying data structure. Tuples are much faster for small elements such as a point. You may retain the clarity of a dictionary by using namedtuple if you so desire.
>>> from collections import namedtuple
>>> A = [
[{'x': 1, 'y': 0}, {'x': 2, 'y': 3}, {'x': 3, 'y': 4}, {'x': 4, 'y': 7}],
[{'x': 1, 'y': 0}, {'x': 2, 'y': 2}, {'x': 3, 'y': 13}, {'x': 4, 'y': 0}],
[{'x': 1, 'y': 20}, {'x': 2, 'y': 4}, {'x': 3, 'y': 0}, {'x': 4, 'y': 8}]
]
Making a Point namedtuple is simple
>>> Point = namedtuple('Point', 'x y')
This is what an instance looks like
>>> Point(x=1, y=0) # Point(1, 0) also works
Point(x=1, y=0)
A would then look like this
>>> A = [[Point(**y) for y in x] for x in A]
>>> A
[[Point(x=1, y=0), Point(x=2, y=3), Point(x=3, y=4), Point(x=4, y=7)],
[Point(x=1, y=0), Point(x=2, y=2), Point(x=3, y=13), Point(x=4, y=0)],
[Point(x=1, y=20), Point(x=2, y=4), Point(x=3, y=0), Point(x=4, y=8)]]
Now working like this is much easier:
>>> from operator import attrgetter
>>> [max(row, key=attrgetter('y')) for row in A]
[Point(x=4, y=7), Point(x=3, y=13), Point(x=1, y=20)]
To retain the speed advantages of tuples it's better to access by index:
>>> from operator import itemgetter
>>> [max(row, key=itemgetter(2)) for row in A]
[Point(x=4, y=7), Point(x=3, y=13), Point(x=1, y=20)]
result=[]
for item in a:
new = sorted(item, key=lambda k: k['y'],reverse=True)
result.append((new[0]['x'],new[0]['y']))
print(result)
Note-The is not the efficient way to do this but this is one of the ways to get the required result.

Categories

Resources