What is the best way to merge two lists into one and also combine double values? For example:
list_01 = [['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-06'],
['10', '20', '30', '40']]
list_02 = [['2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07'],
['10', '20', '30', '40']]
The final list should look like this:
list_03 = [['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07'],
['10', '20', '40', '30', '70', '40']]
Whenever the dates have matched, the integer-values in the second column have been summed together.
Right now, my only real solution is to pass both lists trough several loops, but I wonder if there might be a better solution.
Thanks and a great evening for all of you.
Your "integers" should really be ints, not strings, and your lists should probably be Counters, as you seem to be counting things per day. Then you can simply add them:
from collections import Counter
list_01 = [['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-06'],
['10', '20', '30', '40']]
list_02 = [['2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07'],
['10', '20', '30', '40']]
def to_counter(lst):
return Counter(dict(zip(lst[0], map(int, lst[1]))))
counter = to_counter(list_01) + to_counter(list_02)
for item in counter.items():
print(item)
Prints:
('2020-01-02', 10)
('2020-01-03', 20)
('2020-01-04', 40)
('2020-01-06', 70)
('2020-01-05', 20)
('2020-01-07', 40)
Try this, make dictionaries. Let me know if this isn't what you want or is confusing.
dict_01 = {list_01[0][i]:int(list_01[1][i]) for i in range(len(list_01[0]))}
dict_02 = {list_02[0][i]:int(list_02[1][i]) for i in range(len(list_02[0]))}
dates = list(set(list_01[0] + list_02[0]))
dates.sort()
list_03 = [dates, [dict_01.get(date, 0) + dict_02.get(date, 0) for date in dates]]
#Tomerikoo points out a more elegant way to form the dictionaries.
dict_01 = dict(zip(*list_01))
dict_02 = dict(zip(*list_02))
As #HeapOverflow points out if you do this you should change the sums.
list_03 = [dates, [int(dict_01.get(date, 0)) + int(dict_02.get(date, 0)) for date in dates]]
This returns
[['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07'], [10, 20, 40, 20, 70, 40]]
I think this is right, and the 2020-01-05 should be 20 not 30.
The best way to do it would probably be to use defaultdict, which provides a default value to each key, even if you've never introduced that key to the dictionary before. Then all you have to do is add whatever value belongs to that key (which is the date) from both lists. Then when you have this dictionary, just get the key-value pairs as items and unzip it into two lists.
from collections import defaultdict
mydict = defaultdict(int) # default values are 0
list_01 = [['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-06'], ['10', '20', '30', '40']]
list_02 = [['2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07'], ['10', '20', '30', '40']]
for t in [list_01, list_02]:
for key, value in zip(t[0], t[1]):
mydict[key] += int(value)
print(list(zip(*sorted(mydict.items()))))
This prints:
[('2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-06','2020-01-07'),
(10, 20, 40, 20, 70, 40)]
Related
I have a csv file with actions in them:
Action Name,Price,Benefit
Action-1,20,5,1.0
Action-2,30,10,3.0
Action-3,50,15,7.5
Action-4,70,20,14.0
Action-5,60,17,10.2
Action-6,80,25,20.0
Action-7,22,7,1.54
Action-8,26,11,2.86
I transform it into a list:
rows = []
with open("files/actions_with_benefits.csv", 'r') as file:
csv_reader = csv.reader(file)
header = next(csv_reader)
for row in csv_reader:
rows.append(row)
print("header", header)
print("rows", rows)
rows:
[['Action-1', '20', '5', 1.0], ['Action-2', '30', '10', 3.0], ['Action-3', '50', '15', 7.5], ['Action-4', '70', '20', 14.0], ['Action-5', '60', '17', 10.2], ['Action-6', '80', '25', 20.0], ['Action-7', '22', '7', 1.54], ['Action-8', '26', '11', 2.86], ['Action-9', '48', '13', 6.24], ['Action-10', '34', '27', 9.18], ['Action-11', '42', '17', 7.14]]
I originally needed to calculate all the combinations of the different actions I could buy with 500 dollars (I could only buy 1 of each).
I used combinations to do this (I filtered my actions list to create a list with only the prices of the actions, which I called numbers):
target = 500
result = [seq for i in range(len(numbers), 0, -1)
for seq in itertools.combinations(numbers, i)
if sum(seq) == target]
But I was wondering if I could do that without filtering the other values like the name of the action for exemple and the benefit because I need them.
For exemple in the sort() method, you can use a lambda that allows you to sort on only 1 element in your list but returns the list sorted with all the elements.
Like in this exemple I found:
Input : [['rishav', 10], ['akash', 5], ['ram', 20], ['gaurav', 15]]
def Sort(sub_li):
sub_li.sort(key = lambda x: x[1])
return sub_li
sub_li =[['rishav', 10], ['akash', 5], ['ram', 20], ['gaurav', 15]]
print(Sort(sub_li))
Output : [['akash', 5], ['rishav', 10], ['gaurav', 15], ['ram', 20]]
Do you know if there is a possibility to do this with itertools.combinations?
Thank you in advance for your help and have a lovely day 😊
Just a simple alternative: run two combinations in parallel. Probably faster than stuffing a lambda into sum (though I guess speed isn't an issue, otherwise you wouldn't use brute force anyway)
result = [rowseq
for i in range(len(numbers), 0, -1)
for seq, rowseq in zip(
itertools.combinations(numbers, i),
itertools.combinations(rows, i)
)
if sum(seq) == target]
My code:
import openpyxl
workbook = openpyxl.load_workbook('master.xlsx')
worksheet = workbook.worksheets[0]
result = {}
for k, v in zip(worksheet['A'], worksheet['B']):
result[k.internal_value] = v.internal_value
print(result)
The output I get:
{'PPPPP': '22', 'bbbbb': '20', 'ccccc': '30', 'ddddd': '40', 'eeeee': '50'}
Excel file:
The output I want:
{'PPPPP': ['22','10'], 'bbbbb': ['20','30'], 'ccccc': ['30','30'], 'ddddd': '40', 'eeeee': '50'}
You can do it using pandas
import pandas as pd
df = pd.read_excel('master.xlsx', 0, None, ['A', 'B'])
result = {}
for x, y in zip(df['A'], df['B']):
if x in result:
result[x] = [result.get(x)]
result[x].append(str(y))
else:
result[x] = str(y)
print(result)
{'ppp': ['10', '22'], 'bbb': ['20', '30'], 'ccc': ['30', '30'], 'ddd': '40', 'eee': '50'}
Use a defaultdict, with an empty list as the default, and append each new value:
from collections import defauldict
import openpyxl
workbook = openpyxl.load_workbook('master.xlsx')
worksheet = workbook.worksheets[0]
result = defaultdict(list)
for k, v in zip(worksheet['A'], worksheet['B']):
result[k.internal_value].append(v.internal_value)
print(result)
Here EVERY result will be a list, even when you only have one value. e.g. you will get 'ddddd': ['40'] but you should be able to handle all key value pairs consistently.
Any way to create dictionary of dictionaries of lists in one line?
names = ['alex', 'ben', 'coby']
age = ['20', '30', '40', '50']
name_age = {n: {} for n in names}
for n in names:
name_age[n] = {a: {} for a in age}
Nesting such as below does not work.
name_age = {n: {{a: {} for a in age}} for n in names}
The fastest way of constructing a dictionary based on two lists is iterating them at the same time with zip. This will work:
names = ['alex', 'ben', 'coby']
age = ['20', '30', '40', '50']
name_age = dict(zip(names, age))
print(name_age)
>>> {'alex': '40', 'ben': '50', 'coby': '20'}
names = ['alex', 'ben', 'coby']
ages = ['20', '30', '40', '50']
result = { names[index]:ages[index] for index in range(len(names)) }
print(result)
{'alex': '20', 'ben': '30', 'coby': '40'}
This question already has answers here:
How to sort a list of lists by a specific index of the inner list?
(12 answers)
Closed 3 years ago.
I've started Python recently and came up with a project that gives me a 2 dimensions list.
list = [
['Symbol', 'Price', 'Number', 'Currency'],
['MSFT', '100', '25', 'USD'],
['AAPL', '200', '10', 'USD'],
['TSLA', '245', '30', 'USD']
]
And I want to sort it by the column Number. I found a way, but it involves three loops to print it.
(I looked but couldn't find an answer to my question. Sorry if it already exists)
final_list = [] # To store the ordered items
list_of_numbers = [] # To get the list of item[2]
for item in list: # For every row in the list
if item[2] != "Number": # To not take into account the first line
list_of_numbers.append(int(item[2])) #Â Add the number to the list
list_of_numbers.sort() # Sort the list of numbers
for i in range(1, len(list)): # To get through every row, without the first
index = list_of_numbers[i-1] #Â To find each number of the list_of_numbers
for item in list:
if item[2] == "Number": # Not the first row
pass
elif int(item[2]) == index:
final_list.append(item) # Add the row in the numeric order
break
for item in final_list:
print(item)
The output is the following, and what I want:
['AAPL', '200', '10', 'USD']
['MSFT', '100', '25', 'USD']
['TSLA', '245', '30', 'USD']
But, I really think it's not optimum. Would their be a way to do the same in a more efficient way ?
Thanks a lot and have a nice day.
Here is a simple way to do it:
>>> list = [
... ['Symbol', 'Price', 'Number', 'Currency'],
... ['MSFT', '100', '25', 'USD'],
... ['AAPL', '200', '10', 'USD'],
... ['TSLA', '245', '30', 'USD']
... ]
>>> sorted(list[1:], key=lambda x: x[2])
>>>[['AAPL', '200', '10', 'USD'], ['MSFT', '100', '25', 'USD'], ['TSLA', '245', '30', 'USD']]
I have a dictionary that looks like this:
scores = {'Ben': ['10', '9'], 'Alice': ['10', '10'], 'Tom': ['9', '8']}
I have calculated the average of the values for each person in the dictionary and I want to then store the averages in a separate dictionary. I would like it to look like this:
averages = {'Ben': [9.5], 'Alice': [10], 'Tom': [8.5]}
I have calculated the averages using this code:
for key, values in scores.items():
avg = float(sum([int(i) for i in values])) / len(values)
print(avg)
This gives the following output:
9.5
10.0
8.5
How can I output the averages in a separate dictionary as shown above?
Thanks in advance.
averages = {} # Create a new empty dictionary to hold the averages
for key, values in scores.items():
averages[key] = float(sum([int(i) for i in values])) / len(values)
# Rather than store the averages in a local variable, store them in under the appropriate key in your new dictionary.
Use dict_comprehension.
>>> scores = {'Ben': ['10', '9'], 'Alice': ['10', '10'], 'Tom': ['9', '8']}
>>> {i:[float(sum(int(x) for x in scores[i]))/len(scores[i])] for i in scores}
{'Ben': [9.5], 'Alice': [10.0], 'Tom': [8.5]}
You can use a dictionary comprehension to loop over your items and calculate the proper result:
>>> from __future__ import division
>>> scores = {'Ben': ['10', '9'], 'Alice': ['10', '10'], 'Tom': ['9', '8']}
>>> scores = {k:[sum(map(int,v))/len(v)] for k,v in scores.items()}
>>> scores
{'Ben': [9.5], 'Alice': [10.0], 'Tom': [8.5]}
Note that you need to convert your values to int that you can do it with map function map(int,v).
you can do this with a dict comprehension in one line:
averages = {k: sum(float(i) for i in v) / len(v) for k, v in scores.items() if v}