Currently I have a list of items someone can buy as follows:
my_list = [ ('Candy', 1.0, 20.5), ('Soda', 3.0, 10.25), ('Coffee', 1.2, 20.335), ('Soap', 1.2, 11.5), ('Spoon', 0.2, 2.32), ('Toast', 3.2, 12.335), ('Toothpaste', 3, 20.5), ('Creamer', .1, 5.5), ('Sugar', 2.2, 5.2), ]
Each item is set up like this:
('Item Name', ItemCost, ItemValue)
I have the list pulling the items with the top 5 ItemValue
.
print nlargest(5, my_list, key=itemgetter(2)) >>> [ ('Candy', 1.0, 20.5), ('Toothpaste', 3, 20.5), ('Coffee', 1.2, 20.335), ('Toast', 3.2, 12.335), ('Soap', 1.2, 11.5), ]
I am trying to retrieve a result where I get the top 5 total ItemValue
where the top 5 total ItemCost
is equal or less than 6.
Any suggestions?
9 Answers
Answers 1
You can filter first, and use all following nlargest
on your filtered list.
f = [(a,b,c) for (a,b,c) in my_list if b <= 6]
But for data manipulation like this, pandas
can be very useful. Take, for example
df = pd.DataFrame(my_list, columns=('ItemName', 'ItemCost', 'ItemValue')) ItemName ItemCost ItemValue 0 Candy 1.0 20.500 1 Soda 3.0 10.250 2 Coffee 1.2 20.335 3 Soap 1.2 11.500 4 Spoon 0.2 2.320 5 Toast 3.2 12.335 6 Toothpaste 3.0 20.500 7 Creamer 0.1 5.500 8 Sugar 2.2 5.200 >>> df[df.ItemCost <= 6] ItemName ItemCost ItemValue 0 Candy 1.0 20.500 1 Soda 3.0 10.250 2 Coffee 1.2 20.335 3 Soap 1.2 11.500 4 Spoon 0.2 2.320 5 Toast 3.2 12.335 6 Toothpaste 3.0 20.500 7 Creamer 0.1 5.500 8 Sugar 2.2 5.200 >>> df[df.ItemCost <= 6].nlargest(n=5, columns=['ItemValue']) ItemName ItemCost ItemValue 0 Candy 1.0 20.500 6 Toothpaste 3.0 20.500 2 Coffee 1.2 20.335 5 Toast 3.2 12.335 3 Soap 1.2 11.500
If you want, you can first get the nsmallest
of the ItemCost
and just then get the nlargest
df.nsmallest(n=5, columns=['ItemCost']).nlargest(n=5, columns=['ItemValue']) ItemName ItemCost ItemValue 0 Candy 1.0 20.500 2 Coffee 1.2 20.335 3 Soap 1.2 11.500 7 Creamer 0.1 5.500 4 Spoon 0.2 2.320
Answers 2
Not sure if this is what you asking,
I would first create all possible combinations of 5 elements from my_list
itertools.combinations(my_list, 5)
Then i would find all possible combinations in result where total item cost would be less than or equal to 6.
f = [element for element in itertools.combinations(my_list, 5) if sum([e[1] for e in element]) <=6]
Now, I would find that element where total itemValue is the greatest
h = [sum([g[2] for g in e]) for e in f]
The index of element with maximum itemValue is
index = h.index(max(h))
Now, you can find that element in f.
f[index]
The answer i got is
Candy 1.0 20.5 Coffee 1.2 20.335 Spoon 0.2 2.32 Toothpaste 3 20.5 Creamer 0.1 5.5
Answers 3
First you want to filter the list by the ItemCost
:
Which can be done by:
filtered_generator = filter(lambda x: x[1] <= 6, my_list)
Or in a more python-like way
filtered_list = [x for x in my_list if x[1] <=6]
And to keep it a generator to save memory just use parentheses instead of the square brackets.
Then you want to get the n largest items:
- You can use heapq.nlargest:
nlargest(5, filtered_iter, key=lambda x:x[2])
- or implement similar function yourself.
filtered_iter
can be the list or one of the generators.
Answers 4
from operator import itemgetter from itertools import combinations from beautifultable import BeautifulTable def pretty_print( lst): table = BeautifulTable() table.column_headers = ['Item Name','ItemCost','ItemValue'] if lst: for item_specs in lst: table.append_row(item_specs) print(table) def get_total_cost( lst): return sum(item_specs[1] for item_specs in lst) def get_total_Value( lst): return sum(item_specs[2] for item_specs in lst) def best_comb( item_list, number_of_items_to_pick, cost_constraint): k = number_of_items_to_pick item_list.sort(key=itemgetter(2), reverse=True) # sorting list by ItemValue k_top_value_item_lst = item_list[:5] # picking top k items from list total_cost = get_total_cost(k_top_value_item_lst) def generateCombinations( take_default_val_for_best_result = True): k_len_combination_list = list(combinations( item_list, k)) if take_default_val_for_best_result: best_result = []# which meets total itemCost <= 6 condition and have highest total of ItemValue best_result_sum = [0,0] # ItemCost, ItemValue else: best_result = k_top_value_item_lst best_result_sum = [total_cost, get_total_Value(best_result)] best_alternative_lst = [] # if there are any other combination which offer same Value for Cost # ignore first comb as its been already suggested to user for comb in k_len_combination_list: temp_sum = [None,None] temp_sum[0] = get_total_cost( comb) reset_best = False if temp_sum[0] <= cost_constraint: temp_sum[1] = get_total_Value( comb) if best_result_sum[1] < temp_sum[1]: reset_best = True elif best_result_sum[1] == temp_sum[1]: if temp_sum[0] < best_result_sum[0]: reset_best = True elif temp_sum[0] == best_result_sum[0]: # since ItemValue as well as ItemCost are equivalent to best_result this comb is great alternative if comb != tuple(best_result): best_alternative_lst.append(comb) if reset_best: best_result = comb best_result_sum[1] = temp_sum[1] best_result_sum[0] = temp_sum[0] print('Best Combination:') if best_result: pretty_print(best_result) else: print('not found') if gen_alternative: print('\nBest Alternative Combination:') if best_alternative_lst: for idx,alter_comb in enumerate( best_alternative_lst): comb_id = idx+1 print('combination_id ',comb_id) pretty_print(alter_comb) else: print('not found') if total_cost > cost_constraint: generateCombinations() else: if gen_alternative: generateCombinations(take_default_val_for_best_result = False) else: print('Best Combination:') pretty_print(k_top_value_item_lst) my_list = [ ('Candy', 2.0, 20.5), ('Soda', 1.5, 25.7 ), ('Coffee', 2.4, 25.7 ), ('Soap', 1.2,20), ('Spoon',1.2,20 ), ('Toast',1.2,22 ), ('Toothpaste',0.8, 20 ), ('Creamer',0.8, 22), ('Sugar',2.0, 20.5 ), ] gen_alternative = input('do you want to generate alternative combinations: y/n ')[0].lower() == 'y' best_comb( my_list, 5, 6)
Answer to modified list ( to show extra feature)
do you want to generate alternative combinations: y/n Y Best Combination: +------------+----------+-----------+ | Item Name | ItemCost | ItemValue | +------------+----------+-----------+ | Soda | 1.5 | 25.7 | +------------+----------+-----------+ | Toast | 1.2 | 22 | +------------+----------+-----------+ | Creamer | 0.8 | 22 | +------------+----------+-----------+ | Soap | 1.2 | 20 | +------------+----------+-----------+ | Toothpaste | 0.8 | 20 | +------------+----------+-----------+ Best Alternative Combination: combination_id 1 +------------+----------+-----------+ | Item Name | ItemCost | ItemValue | +------------+----------+-----------+ | Soda | 1.5 | 25.7 | +------------+----------+-----------+ | Toast | 1.2 | 22 | +------------+----------+-----------+ | Creamer | 0.8 | 22 | +------------+----------+-----------+ | Spoon | 1.2 | 20 | <--- +------------+----------+-----------+ | Toothpaste | 0.8 | 20 | +------------+----------+-----------+
Answer to your original list
Best Combination: +------------+----------+-----------+ | Item Name | ItemCost | ItemValue | +------------+----------+-----------+ | Candy | 1.0 | 20.5 | +------------+----------+-----------+ | Toothpaste | 3 | 20.5 | +------------+----------+-----------+ | Coffee | 1.2 | 20.335 | +------------+----------+-----------+ | Creamer | 0.1 | 5.5 | +------------+----------+-----------+ | Spoon | 0.2 | 2.32 | +------------+----------+-----------+ Best Alternative Combination: not found
Answers 5
Not totally sure of what you are trying to do, but...
If you are trying to retrieve the top x (5 or 6) based on itemcost
sorted by lowest cost, you can try this.
x=5 sorted(my_list, key=lambda s : s[2])[:x] This outputs the following: [('Spoon', 0.2, 2.32), ('Sugar', 2.2, 5.2), ('Creamer', 0.1, 5.5), ('Soda', 3.0, 10.25), ('Soap', 1.2, 11.5)]
Answers 6
from itertools import combinations ... total_cost = lambda item: int(sum(c for _, c, _ in item) <= 6) * sum(v for _, _ , v in item) chosen = max(combinations(my_list, 5), key=total_cost)
Max can receive a function to specify max criteria.
The total_cost function, has a int(sum(c for _, c, _ in item) <= 6) portion that is 1 if total cost of the combination is less or equal then 6, and its 0 otherwise.
We then multiply this portion with the total sum of values.
combinations(my_list, 5) retrieves all possible combinations of my_list items having 5 items.
Printing chosen elements you have:
('Candy', 1.0, 20.5) ('Coffee', 1.2, 20.335) ('Spoon', 0.2, 2.32) ('Toothpaste', 3, 20.5) ('Creamer', 0.1, 5.5)
Answers 7
Filter the list first:
print nlargest(5, [item for item in my_list if item[1]<=6], key=itemgetter(2))
You can do it with sorted too:
sorted([item for item in my_list if item[1]<=6], key=lambda x: x[1], reverse=True)[:5]
The above filters out items with ItemCost greater than 6, sorts your list descending based on ItemCost, and then returns the first 5 element
Answers 8
First using combinations
we can get all possible combinations of 5 from my_list
. From here we can use filter
and only return combinations whose total ItemCost
is less than or equal to 6
. Finally we sort by the which group has the highest total ItemValue
and we take the greatest one being l2[-1]
we could use reverse = True
and then it would be l2[0]
from itertools import combinations
l = list(combinations(my_list, 5)) l1 = list(filter(lambda x: sum([i[1] for i in x]) < 6, l)) l2 = sorted(l1, key=lambda x: sum([i[2] for i in x])) print(l2[-1])
(('Candy', 1.0, 20.5), ('Coffee', 1.2, 20.335), ('Spoon', 0.2, 2.32), ('Toothpaste', 3, 20.5), ('Creamer', 0.1, 5.5))
Answers 9
from itertools import combinations from functools import reduce def get_valid_combs(lis): "find all combinations that cost less than or equal to 6" for i in combinations(lis, 5): if reduce(lambda acc, x: acc + x[1], list(i), 0) <= 6: yield list(i) my_list = [ ('Candy', 1.0, 20.5), ('Soda', 3.0, 10.25), ('Coffee', 1.2, 20.335), ('Soap', 1.2, 11.5), ('Spoon', 0.2, 2.32), ('Toast', 3.2, 12.335), ('Toothpaste', 3, 20.5), ('Creamer', .1, 5.5), ('Sugar', 2.2, 5.2), ] # find all valid combinations which cost less than 6 valid_combinations = [i for i in get_valid_combs(my_list)] #top_combinations_sorted = sorted(valid_combinations, key=lambda y: reduce(lambda acc, x: acc + x[2], [0]+y)) # of the valid combinations get the combination with highest total value best_combination = max(valid_combinations, key=lambda y: reduce(lambda acc, x: acc + x[2], y, 0)) print(best_combination)
output:
[('Candy', 1.0, 20.5), ('Coffee', 1.2, 20.335), ('Spoon', 0.2, 2.32), ('Toothpaste', 3, 20.5), ('Creamer', 0.1, 5.5)]
0 comments:
Post a Comment