Related
I have this data :
[
{'name': 'INV/2021/0913', 'invoice_date': datetime.date(2021, 3, 12), 'qty_total': 5.0},
{'name': 'INV/2021/0965', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 6.0},
{'name': 'INV/2021/0966', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 7.0},
{'name': 'INV/2021/0967', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 3.0},
{'name': 'INV/2021/0992', 'invoice_date': datetime.date(2021, 3, 15), 'qty_total': 4.0}
]
As it can be seen the middle 3 dicts have same date.
I want to combine the dictionaries having the same invoice_date and sum up the its qty_total.
Set the name attribute to "" for the combined dictionaries.
The result should look like this:
[
{'name': 'INV/2021/0913', 'invoice_date': datetime.date(2021, 3, 12), 'qty_total': 5.0},
{'name': '', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 16.0},
{'name': 'INV/2021/0992', 'invoice_date': datetime.date(2021, 3, 15), 'qty_total': 4.0}
]
use itertools.groupby
from datetime import datetime
from itertools import groupby
l = [
{'name': 'INV/2021/0913', 'invoice_date': datetime(2021, 3, 12).date(), 'qty_total': 5.0},
{'name': 'INV/2021/0965', 'invoice_date': datetime(2021, 3, 14).date(), 'qty_total': 6.0},
{'name': 'INV/2021/0966', 'invoice_date': datetime(2021, 3, 14).date(), 'qty_total': 7.0},
{'name': 'INV/2021/0967', 'invoice_date': datetime(2021, 3, 14).date(), 'qty_total': 3.0},
{'name': 'INV/2021/0992', 'invoice_date': datetime(2021, 3, 15).date(), 'qty_total': 4.0}
]
res = []
for k, v in groupby(sorted(l, key=lambda x: x["invoice_date"]), key=lambda x: (x["invoice_date"])):
val = list(v)
res.append(
{"name": " " if len(val)>1 else val[0]["name"], "invoice_date": k, "qty_total": sum(vals["qty_total"] for vals in val)}
)
print(res)
Output
[{'name': 'INV/2021/0913',
'invoice_date': datetime.date(2021, 3, 12),
'qty_total': 5.0},
{'name': ' ', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 16.0},
{'name': 'INV/2021/0992',
'invoice_date': datetime.date(2021, 3, 15),
'qty_total': 4.0}]
{'YOU': {'HE': {'EST': 8, 'OLM': 6}, 'SLO': {'WLR': 8}},
'ARE': {'KLP': {'EST': 6}, 'POL': {'WLR': 4}},
'DOING': {'TIS': {'OIL': 8}},
'GREAT': {'POL': {'EOL': 6}},
'WORK': {'KOE': {'RIW': 8, 'PNG': 4}, 'ROE': {'ERC': 8, 'WQD': 6}},
'KEEP': {'PAR': {'KOM': 8, 'RTW': 6}, 'PIL': {'XCE': 4, 'ACE': 8}},
'ROCKING': {'OUL': {'AZS': 6, 'RVX': 8}}}
Need to perform a calculation on the numbers in dictionary.
Eg: {'YOU': {'HE': {'EST': 8, 'OLM': 6}, 'SLO': {'WLR': 8}},
'WORK': {'KOE': {'RIW': 8, 'PNG': 4}, 'ROE': {'ERC': 8, 'WQD': 6}}} for this example the output would be
[(8+6)x8]+[(8+4)x(8+6)]
[14x8]+[12x14]
112+168
280
Following is the code I tried :
a = [tuple([k]+list(v.keys())+list(j.values())) for k,v in data.items() for i,j in v.items()]
and it gives :
[('YOU', 'HE', 'SLO', 8, 6),
('YOU', 'HE', 'SLO', 8),
('ARE', 'KLP', 'POL', 6),
('ARE', 'KLP', 'POL', 4),
('DOING', 'TIS', 8),
('GREAT', 'POL', 6),
('WORK', 'KOE', 'ROE', 8, 4),
('WORK', 'KOE', 'ROE', 8, 6),
('KEEP', 'PAR', 'PIL', 8, 6),
('KEEP', 'PAR', 'PIL', 4, 8),
('ROCKING', 'OUL', 6, 8)]
The rules aren't well-defined, but I'll give it a shot anyway. I am assuming you only want this calculation to apply to keys YOU and WORK in your nested dictionary. I think a list comprehension will get pretty complicated, and it's more readable to work with loops.
For each key YOU and WORK, I summed up these two innermost sets of values 8+6, 8 for YOU and 8+4, 8+6 for WORK, multiplied these values together 14*8 for YOU and 12*14 for WORK, then added the products together to get the result = 280
dict_nested = {'YOU': {'HE': {'EST': 8, 'OLM': 6}, 'SLO': {'WLR': 8}},
'ARE': {'KLP': {'EST': 6}, 'POL': {'WLR': 4}},
'DOING': {'TIS': {'OIL': 8}},
'GREAT': {'POL': {'EOL': 6}},
'WORK': {'KOE': {'RIW': 8, 'PNG': 4}, 'ROE': {'ERC': 8, 'WQD': 6}},
'KEEP': {'PAR': {'KOM': 8, 'RTW': 6}, 'PIL': {'XCE': 4, 'ACE': 8}},
'ROCKING': {'OUL': {'AZS': 6, 'RVX': 8}}}
keys = ['YOU','WORK']
result = 0
for key in keys:
inner_keys = dict_nested[key].keys()
# multiply the values together for the first values of the inner key
inner_product = 1
for inner_key in inner_keys:
inner_product *= sum(list(dict_nested[key][inner_key].values()))
# print(inner_product)
result += inner_product
Output:
>>> result
280
NOTE
By any means don't use eval, it is insecure ("eval is evil").
For more details about eval harmfulness (there are too many, I've just cherry-picked one) read here.
Some Inspiration Towards a Solution
As others and smarter before me have noted, I haven't found any reasonable explanation regarding the operands assignment in the example you've provided.
However, this is a little try - hope it will help you with the challenge.
So here you go:
import json
d = {'YOU': {'HE': {'EST': 8, 'OLM': 6}, 'SLO': {'WLR': 8}}, 'WORK': {'KOE': {'RIW': 8, 'PNG': 4}, 'ROE': {'ERC': 8, 'WQD': 6}}}
# Convet dictionary to a string
r = json.dumps(d)
# Convert string to char list
chars = list(r)
# Legal chars needed for computing
legal_chars = ['{', '}', ','] + [str(d) for d in range(10)]
# Filtering in only legal chars
filtered_chars = [x for x in chars if x in legal_chars]
# Replacing the {} with () and , with +
expression = ''.join(filtered_chars).replace('{', '(').replace('}', ')').replace(',', '+')
# Evaluating expression
result = eval(expression)
# (((8+6)+(12))+((8+4)+(8+6)))=52
print(f'{expression}={result}')
I would like to create nested dict in python3, I've the following list(from a sql-query):
[('madonna', 'Portland', 'Oregon', '0.70', '+5551234', 'music', datetime.date(2016, 9, 8), datetime.date(2016, 9, 1)), ('jackson', 'Laredo', 'Texas', '2.03', '+555345', 'none', datetime.date(2016, 5, 23), datetime.date(2016, 5, 16)), ('bohlen', 'P', 'P', '2.27', '+555987', 'PhD Student', datetime.date(2016, 9, 7))]
I would like to have the following output:
{madonna:{city:Portland, State:Oregon, Index: 0.70, Phone:+5551234, art:music, exp-date:2016, 9, 8, arrival-date:datetime.date(2016, 5, 23)},jackson:{city: Laredo, State:Texas........etc...}}
Can somebody show me an easy to understand code?
I try:
from collections import defaultdict
usercheck = defaultdict(list)
for accname, div_ort, standort, raum, telefon, position, exp, dep in cur.fetchall():
usercheck(accname).append[..]
but this don't work, I can't think any further myself
You can use Dict Comprehension (defined here) to dynamically create a dictionary based on the elements of a list:
sql_list = [
('madonna', 'Portland', 'Oregon', '0.70', '+5551234', 'music', datetime.date(2016, 9, 8), datetime.date(2016, 9, 1)),
('jackson', 'Laredo', 'Texas', '2.03', '+555345', 'none', datetime.date(2016, 5, 23), datetime.date(2016, 5, 16)),
('bohlen', 'P', 'P', '2.27', '+555987', 'PhD Student', datetime.date(2016, 9, 7))
]
sql_dict = {
element[0]: {
'city': element[1],
'state': element[2],
'index': element[3],
'phone': element[4],
'art': element[5],
} for element in sql_list
}
Keep in mind that every item in the dictionary needs to have a key and a value, and in your example you have a few values with no key.
If you have a list of the columns, you can use the zip function:
from collections import defaultdict
import datetime
# list of columns returned from your database query
columns = ["city", "state", "index", "phone", "art", "exp-date", "arrival-date"]
usercheck = defaultdict(list)
for row in cur.fetchall():
usercheck[row[0]] = defaultdict(list, zip(columns, row[1:]))
print usercheck
This will output a dictionary like:
defaultdict(<type 'list'>, {'madonna': defaultdict(<type 'list'>, {'city': 'Portland', 'art': 'music', 'index': '0.70', 'phone': '+5551234', 'state': 'Oregon', 'arrival-date': datetime.date(2016, 9, 1), 'exp-date': datetime.date(2016, 9, 8)}), 'jackson': defaultdict(<type 'list'>, {'city': 'Laredo', 'art': 'none', 'index': '2.03', 'phone': '+555345', 'state': 'Texas', 'arrival-date': datetime.date(2016, 5, 16), 'exp-date': datetime.date(2016, 5, 23)}), 'bohlen': defaultdict(<type 'list'>, {'city': 'P', 'art': 'PhD Student', 'index': '2.27', 'phone': '+555987', 'state': 'P', 'arrival-date': None, 'exp-date': datetime.date(2016, 9, 7)})})
When using defaultdict, the argument specifies the default value type in the dictionary.
from collections import defaultdict
usercheck = defaultdict(dict)
for accname, div_ort, standort, raum, telefon, position, exp, dep in cur.fetchall():
usercheck[accname]['city'] = div_ort
usercheck[accname]['state'] = standout
...
The keys in the dictionary are referenced using [key], not (key).
I want to change this in python
Before :
{'NewYork': {'Paris': 12, 'Hawaii': 8, 'Tokyo': 11, 'Incheon': 12, 'LA': 2},
'Beijing': {'Hongkong': 3, 'Cebu': 5},
'Incheon': {'Cairo': 10, 'LA': 11, 'Tokyo': 1},
'Tokyo': {'NewYork': 12, 'Paris': 14, 'LA': 9}}
After :
[("NewYork","Paris",12),
("NewYork","Hawaii",8),
("Newyork","Tokyo",11),
("NewYork","Incheon",12),
("NewYork","LA",2),
("Beijing","HongKong",3),
("Beijing","Cebu",5),
("Incheon","Cairo",10),
("Incheon","LA",11),
("Incheon","Tokyo",1),
("Tokyo","NewYork",12),
("Tokyo","Paris",14),
("Tokyo","LA",9)]
How can I do this?
>>> before = {'NewYork': {'Paris': 12, 'Hawaii': 8, 'Tokyo': 11, 'Incheon': 12, 'LA': 2},
... 'Beijing': {'Hongkong': 3, 'Cebu': 5}, 'Incheon': {'Cairo': 10, 'LA': 11, 'Tokyo': 1},
... 'Tokyo': {'NewYork': 12, 'Paris': 14, 'LA': 9}}
>>>
>>> print [(key,k,v) for key,val in before.iteritems() for k,v in val.iteritems()]
[('NewYork', 'Paris', 12), ('NewYork', 'LA', 2), ('NewYork', 'Hawaii', 8), ('NewYork', 'Incheon', 12), ('NewYork', 'Tokyo', 11), ('Beijing', 'Hongkong', 3), ('Beijin
g', 'Cebu', 5), ('Incheon', 'Cairo', 10), ('Incheon', 'Tokyo', 1), ('Incheon', 'LA', 11), ('Tokyo', 'NewYork', 12), ('Tokyo', 'Paris', 14), ('Tokyo', 'LA', 9)]
You can create an array with a list comprehension and two lots of iteration:
>>> city_pairings = {'NewYork': {'Paris': 12,
... 'Hawaii': 8,
... 'Tokyo': 11,
... 'Incheon': 12,
... 'LA': 2},
... 'Beijing': {'Hongkong': 3,
... 'Cebu': 5},
... 'Incheon': {'Cairo': 10,
... 'LA': 11,
... 'Tokyo': 1},
... 'Tokyo': {'NewYork': 12,
... 'Paris': 14,
... 'LA': 9}}
>>> flat = [(city, other_city, value)
... for city, pairings in city_pairings.iteritems()
... for other_city, value in pairings.iteritems()]
>>> from pprint import pprint
>>> pprint(flat)
[('NewYork', 'Paris', 12),
('NewYork', 'LA', 2),
('NewYork', 'Hawaii', 8),
('NewYork', 'Incheon', 12),
('NewYork', 'Tokyo', 11),
('Beijing', 'Hongkong', 3),
('Beijing', 'Cebu', 5),
('Incheon', 'Cairo', 10),
('Incheon', 'Tokyo', 1),
('Incheon', 'LA', 11),
('Tokyo', 'NewYork', 12),
('Tokyo', 'Paris', 14),
('Tokyo', 'LA', 9)]
The second cities aren't exactly in the order you wanted as the dictionary sorts them according to some scheme. To have cities in the order they were inserted into the dictionary you'll have to do something else, using OrderedDict, for example.
This will do the trick:
dict.items()
I want to basically have a sorted list of my list of dictionaries that looks like:
similarity = [{'Ben': 49}, {'Moose': 18}, {'Reuven': 39}, {'Cust1': 58}, {'Cust2': 10}, {'Francois': 58}, {'Jim C': 39}, {'Iren': 13}, {'Cust3': 13}]
Any help is appreciated, and thanks in advance.
You should be using a list of tuples here:
>>> lst = [d.items()[0] for d in similarity]
>>> lst
[('Ben', 49), ('Moose', 18), ('Reuven', 39), ('Cust1', 58), ('Cust2', 10), ('Francois', 58), ('Jim C', 39), ('Iren', 13), ('Cust3', 13)]
Then you can sort those as usual.
>>> from operator import itemgetter
>>> sorted(lst, key=itemgetter(1))
[('Cust2', 10), ('Iren', 13), ('Cust3', 13), ('Moose', 18), ('Reuven', 39), ('Jim C', 39), ('Ben', 49), ('Cust1', 58), ('Francois', 58)]
If you want, you can also use a single, ordered dictionary to hold the values:
>>> from collections import OrderedDict
>>> OrderedDict(sorted(lst, key=itemgetter(1)))
OrderedDict([('Cust2', 10), ('Iren', 13), ('Cust3', 13), ('Moose', 18), ('Reuven', 39), ('Jim C', 39), ('Ben', 49), ('Cust1', 58), ('Francois', 58)])
This is one way of doing it.
>>> sorted(similarity, key=lambda x: x.values()[0])
[{'Cust2': 10}, {'Iren': 13}, {'Cust3': 13}, {'Moose': 18}, {'Reuven': 39}, {'Jim C': 39}, {'Ben': 49}, {'Cust1': 58}, {'Francois': 58}]
I face difficulty in this.
So I suggest you do in this method
a = {'Ben': 49}
b = {'Moose': 18}
ab = {**a, **b}
print(ab)
{'Ben': 49, 'Moose': 18}
1: sorted(ab.values())
[('Ben', 49), ('Moose', 18)]
2: sorted(ab.items())
[18, 49]