Reputation: 2851
I have a list of lists in python. Each value on the list of lists is represented by [category,type,item,score]. For each category and type, i would like to return a list of highest score items.
[["Edibles", "Fruit", "Apple", 3],
"Edibles", "Fruit", "Grapes", 8],
"Edible", "Candy", "Hershey", 4],
"Edible", "Candy", "Snickers", 6],
"NonEdible", "Bikes", "Yamaha", 5],
"NonEdible", "Bikes", "Suzuki", 7],
"NonEdible", "Cars", "Kia", 8],
"NonEdible", "Cars", "Toyota", 9]]
Desired output
[["Edibles", "Fruit", "Grapes", 8],
"Edible", "Candy", "Snickers", 6],
"NonEdible", "Bikes", "Suzuki", 7],
"NonEdible", "Cars", "Toyota", 9]]
I'm able to do this with multiple loops creating temporary lists, but as the input size increase, the computation becomes very slow. I'm looking for an efficient solution.
Upvotes: 1
Views: 91
Reputation: 62393
import pandas as pd
# setup dataframe
data = [["Edibles", "Fruit", "Apple", 3],
["Edibles", "Fruit", "Grapes", 8],
["Edible", "Candy", "Hershey", 4],
["Edible", "Candy", "Snickers", 6],
["NonEdible", "Bikes", "Yamaha", 5],
["NonEdible", "Bikes", "Suzuki", 7],
["NonEdible", "Cars", "Kia", 8],
["NonEdible", "Cars", "Toyota", 9]]
df = pd.DataFrame(data)
# groupby max
output = df.groupby([0, 1]).agg(max).reset_index()
0 1 2 3
0 Edible Candy Snickers 6
1 Edibles Fruit Grapes 8
2 NonEdible Bikes Yamaha 7
3 NonEdible Cars Toyota 9
# output to a list if you want
output.to_numpy()
array([['Edible', 'Candy', 'Snickers', 6],
['Edibles', 'Fruit', 'Grapes', 8],
['NonEdible', 'Bikes', 'Yamaha', 7],
['NonEdible', 'Cars', 'Toyota', 9]], dtype=object)
Upvotes: 1
Reputation: 18106
You can use a regular dict, storing all values per unique key in a list and just grabbing the max value:
data = [
["Edibles", "Fruit", "Apple", 3],
["Edibles", "Fruit", "Grapes", 8],
["Edible", "Candy", "Hershey", 4],
["Edible", "Candy", "Snickers", 6],
["NonEdible", "Bikes", "Yamaha", 5],
["NonEdible", "Bikes", "Suzuki", 7],
["NonEdible", "Cars", "Kia", 8],
["NonEdible", "Cars", "Toyota", 9]]
dct = {}
for item in data:
dct.setdefault((item[0], item[1]), []).append((item[-2], item[-1]))
for k, v in dct.items():
print(list(k) + list(max(v, key=lambda x: x[1])))
Output:
['Edibles', 'Fruit', 'Grapes', 8]
['Edible', 'Candy', 'Snickers', 6]
['NonEdible', 'Bikes', 'Suzuki', 7]
['NonEdible', 'Cars', 'Toyota', 9]
Upvotes: 1
Reputation: 1415
A simple dictionary is fast and efficient!
(your list-of-lists is malformed - you don't have opening brackets for each sub-list)
You could do this in 1 pass with a dictionary:
input = [["Edibles", "Fruit", "Apple", 3],
["Edibles", "Fruit", "Grapes", 8],
["Edible", "Candy", "Hershey", 4],
["Edible", "Candy", "Snickers", 6],
["NonEdible", "Bikes", "Yamaha", 5],
["NonEdible", "Bikes", "Suzuki", 7],
["NonEdible", "Cars", "Kia", 8],
["NonEdible", "Cars", "Toyota", 9]
]
highest_val_dict = {}
for curr_list in input:
curr_key = (curr_list[0], curr_list[1]) # (category,type) is the key
curr_item = curr_list[2]
curr_val = curr_list[3]
highest_pair = highest_val_dict.get(curr_key, (None, -1))
if curr_val > highest_pair[1]:
highest_val_dict[curr_key] = (curr_item, curr_val)
>>> for key, val in highest_val_dict.items():
>>> print(f'{key[0]}, {key[1]}, {val[0]}, {val[1]}')
Edibles, Fruit, Grapes, 8
Edible, Candy, Snickers, 6
NonEdible, Bikes, Suzuki, 7
NonEdible, Cars, Toyota, 9
Upvotes: 2
Reputation: 34046
You can use pandas
library for this:
Install pandas like:
pip install pandas
Your code would be:
In [2271]: import pandas as pd
In [2272]: l = [["Edibles", "Fruit", "Apple", 3],
...: ["Edibles", "Fruit", "Grapes", 8],
...: ["Edible", "Candy", "Hershey", 4],
...: ["Edible", "Candy", "Snickers", 6],
...: ["NonEdible", "Bikes", "Yamaha", 5],
...: ["NonEdible", "Bikes", "Suzuki", 7],
...: ["NonEdible", "Cars", "Kia", 8],
...: ["NonEdible", "Cars", "Toyota", 9]]
In [2275]: df = pd.DataFrame(l, columns=['category','type','item','score'])
In [2284]: df.groupby(['category','type'], as_index=False).agg(max).values.tolist()
Out[2284]:
[['Edible', 'Candy', 'Snickers', 6],
['Edibles', 'Fruit', 'Grapes', 8],
['NonEdible', 'Bikes', 'Yamaha', 7],
['NonEdible', 'Cars', 'Toyota', 9]]
Upvotes: 1
Reputation: 195418
You can use itertools.groupby
, but you need to sort the list before grouping:
from itertools import groupby
lst = [["Edibles", "Fruit", "Apple", 3],
["Edibles", "Fruit", "Grapes", 8],
["Edible", "Candy", "Hershey", 4],
["Edible", "Candy", "Snickers", 6],
["NonEdible", "Bikes", "Yamaha", 5],
["NonEdible", "Bikes", "Suzuki", 7],
["NonEdible", "Cars", "Kia", 8],
["NonEdible", "Cars", "Toyota", 9]]
#if lst is already sorted, skip this step:
lst = sorted(lst, key=lambda k: (k[0], k[1]))
out = [max(g, key=lambda k: k[-1]) for _, g in groupby(lst, lambda k: (k[0], k[1]))]
from pprint import pprint
pprint(out)
Prints:
[['Edible', 'Candy', 'Snickers', 6],
['Edibles', 'Fruit', 'Grapes', 8],
['NonEdible', 'Bikes', 'Suzuki', 7],
['NonEdible', 'Cars', 'Toyota', 9]]
Upvotes: 4