问题
I have 3 DB calls returning a tuple of tuples with a name, code and count like so:
year = (('Fanklin Grand Isle', '5560', 1), ('Windham', '3457', 1))
month = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '3367', 1))
week = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '3367', 1))
I need to merge these all together so that they will have the Name, code and count for yearly, monthly and weekly.
My problem is that if there is no record I need to insert the Name and code in AND a 0 value for the counts. The end product should be something like:
result = (('Windham', '0905', 1, 1, 0), ('Windsor Windham', '7852', 0, 0, 0), ('Washington', '3292', 0, 0, 0),
('Orleans Essex', '44072', 1, 1, 0), ('Addison', '2853', 0), ('Bennington', '3778', 0),
('Fanklin Grand Isle', '5560', 0, 0 0), ('Caledonia', '1992', 0, 0, 0),
('Rutland', '2395', 1, 0, 0), ('Chittendon', '3367', 1, 1, 0), ('Lamoille', '5229',0, 0 0))
I was trying to nest a loop to check if the name was present in the DB call and the template. IF if was append the DB value to the list, if not append 0
i = 0
for p in newlist:
try:
if p[0] == mlist[i][0]:
print("HERE: {} {}".format(p[0], mlist[i][0]))
p.append(mlist[i][-1])
i += 1
else:
p.append(0)
except IndexError:
continue
This is appending the DB value but not the zero. I am sure there must be a better way to do this and get it to actually work.
Edit
Here is the updated code based on answers received. For me it is still replacing each year
value with a 0.
DATA:
year = (('Fanklin Grand Isle', '5560', 1), ('Windham', '0905', 0), ('Windsor Windham', '7852', 0), ('Washington', '3292', 0), ('Orleans Essex', '44072', 0), ('Chittendon', '18028633367', 1), ('Addison', '12853', 0), ('Bennington', '3778', 0), ('Caledonia', '11992', 0), ('Rutland', '1895', 0), ('Chittendon', '18367', 0), ('Lamoille', '1809', 0), ('Windham', '180905', 0), ('Windsor Windham', '180852', 0), ('Waston', '18022623292', 0), ('Orleans Essex', '18072', 0), ('Addison', '1853', 0), ('Bennington', '1778', 0), ('Fanklin Grand Isle', '18560', 0), ('Caledonia', '180292', 0), ('Rutland', '195', 0), ('Lamoille', '18229', 0))
month = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '18028633367', 1))
week = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '18367', 1))
Code:
from collections import defaultdict
joined_data = defaultdict([0, 0, 0].copy)
for entry in year:
# we create the default entry by calling the defaultdict with a key
# and immediately grab the newly created list
count = joined_data[(entry[0],entry[1])]
# we swap *inplace* the value given by the DB query
count[0] = entry[2]
# rinse and repeat with the rest of the data
for entry in month:
count = joined_data[(entry[0], entry[1])]
count[1] = entry[2]
for entry in week:
count = joined_data[(entry[0], entry[1])]
count[2] = entry[2]
# Finally we format the data to the required format
result = tuple(key+tuple(value) for key,value in joined_data.items() )
print(result)
Result:
(('Fanklin Grand Isle', '5560', 0, 1, 1), ('Windham', '0905', 0, 0, 0), ('Windsor Windham', '7852', 0, 0, 0), ('Washington', '3292', 0, 0, 0), ('Orleans Essex', '1072', 0, 0, 0), ('Chittendon', '13367', 0, 1, 1), ('Addison', '2853', 0, 0, 0), ('Bennington', '1878', 0, 0, 0), ('Caledonia', '1992', 0, 0, 0), ('Rutland', '2395', 0, 0, 0), ('Lamoille', '5229', 0, 0, 0))
回答1:
Here's a way to deal with your issue using a defaultdict
to avoid having to care about the missing entries :
year = (('Fanklin Grand Isle', '5560', 1), ('Windham', '3457', 1))
month = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '3367', 1))
week = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '3367', 1))
#I'm using a defaultdict to deal with the missing entries
from collections import defaultdict
joined_data = defaultdict([0,0,0].copy)
for entry in year:
#we create the default entry by calling the defaultdict with a key
#and immediately grab the newly created list
count = joined_data[(entry[0],entry[1])]
#we swap *inplace* the value given by the DB query
count[0] = entry[2]
#rinse and repeat with the rest of the data
for entry in month:
count = joined_data[(entry[0],entry[1])]
count[1] = entry[2]
for entry in week:
count = joined_data[(entry[0],entry[1])]
count[2] = entry[2]
#Finally we format the data to the required format
result = tuple(key+tuple(value) for key,value in joined_data.items() )
print(result)
Output:
>>>(('Chittendon', '3367', 0, 1, 1), ('Fanklin Grand Isle', '5560', 1, 1, 1), ('Windham', '3457', 1, 0, 0))
回答2:
Not sure I understand what you are trying to achieve, as your example input does not really match your output, but I think you can just use a list comprehension to construct the result, checking whether those items are in the years
, months
and weeks
lists, and adding a 1
or 0
respectively:
>>> year = (('Fanklin Grand Isle', '5560', 1), ('Windham', '3457', 1))
>>> month = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '3367', 1))
>>> week = (('Fanklin Grand Isle', '5560', 1), ('Chittendon', '3367', 1))
>>> [(x[0], x[1], int(x in year), int(x in month), int(x in week)) for x in set(year + week + month)]
[('Chittendon', '3367', 0, 1, 1),
('Windham', '3457', 1, 0, 0),
('Fanklin Grand Isle', '5560', 1, 1, 1)]
If those counts can actually be different from 1
, you should first create a few dictionaries mapping the cities to their respective year/month/week counts, and then use a similar list comprehension as above:
>>> year_counts = {(name, code): count for (name, code, count) in year}
>>> month_counts = {(name, code): count for (name, code, count) in month}
>>> week_counts = {(name, code): count for (name, code, count) in week}
>>> all_cities = [(name, code) for (name, code, count) in set(year + month + week)]
>>> [(x[0], x[1], year_counts.get(x, 0), month_counts.get(x, 0), week_counts.get(x, 0)) for x in all_cities]
[('Chittendon', '3367', 0, 1, 1),
('Windham', '3457', 1, 0, 0),
('Fanklin Grand Isle', '5560', 1, 1, 1)]
来源:https://stackoverflow.com/questions/46774105/merge-multiple-lists-of-lists-based-on-template