繁体   English   中英

获取密钥总数小于或等于X的前5个值

[英]Get top 5 values where key total is less than or equal to X

目前我有一个人可以购买的物品清单如下:

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),
]

每个项目都设置如下:

('Item Name', ItemCost, ItemValue)

我有列表拉出前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),
    ]

我试图检索结果从哪里获得前5名总ItemValue ,其中前5名总ItemCost等于或小于6。

有什么建议么?

您可以先过滤,然后在过滤后的列表中使用以下所有nlargest

f = [(a,b,c) for (a,b,c) in my_list if b <= 6]

但对于像这样的数据操作, pandas可能非常有用。 举个例子吧

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

如果你愿意,你可以先获得nsmallestItemCost然后获得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

不确定这是不是你问的,

我首先要创建my_list中5个元素的所有可能组合

itertools.combinations(my_list, 5)

然后我会在结果中找到所有可能的组合,其中总项目成本将小于或等于6。

f = [element for element in itertools.combinations(my_list, 5) if  sum([e[1] for e in element]) <=6]

现在,我会找到总itemValue最大的元素

h = [sum([g[2] for g in e]) for e in f]

具有最大itemValue的元素的索引是

index = h.index(max(h))

现在,你可以在f中找到该元素。

f[index]

我得到的答案是

 Candy        1.0  20.5
 Coffee       1.2  20.335
 Spoon        0.2  2.32
 Toothpaste   3    20.5
 Creamer      0.1  5.5

首先,您要通过ItemCost过滤列表:

  • 可以通过以下方式完成: filtered_generator = filter(lambda x: x[1] <= 6, my_list)

  • 或者以类似python的方式filtered_list = [x for x in my_list if x[1] <=6]

  • 并保持它是一个节省内存的生成器只需使用括号而不是方括号。

然后你想得到n个最大的项目:

  • 你可以使用heapq.nlargestnlargest(5, filtered_iter, key=lambda x:x[2])
  • 或者自己实现类似的功能。

filtered_iter可以是列表或其中一个生成器。

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)

回答修改清单(显示额外功能)

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     |
+------------+----------+-----------+      

回答原始列表

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

不完全确定你要做什么,但......
如果您尝试根据按最低成本排序的itemcost检索前x(5或6),您可以尝试这样做。

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)]
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)

输出:

[('Candy', 1.0, 20.5), ('Coffee', 1.2, 20.335), ('Spoon', 0.2, 2.32), ('Toothpaste', 3, 20.5), ('Creamer', 0.1, 5.5)]
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可以接收指定最大标准的函数。

total_cost函数具有int(sum(c,_,c,_ in item)<= 6)部分,如果组合的总成本小于或等于6,则为1,否则为0。

然后,我们将此部分乘以值的总和。

组合(my_list,5)检索具有5个项目的my_list项目的所有可能组合。

打印您选择的元素:

('Candy', 1.0, 20.5)
('Coffee', 1.2, 20.335)
('Spoon', 0.2, 2.32)
('Toothpaste', 3, 20.5)
('Creamer', 0.1, 5.5)

首先过滤列表:

print nlargest(5, [item for item in my_list if item[1]<=6], key=itemgetter(2))

您也可以使用排序:

sorted([item for item in my_list if item[1]<=6], key=lambda x: x[1], reverse=True)[:5]

上面过滤掉ItemCost大于6的项目,根据ItemCost对列表进行降序排序 ,然后返回前5个元素

首先使用combinations我们可以从my_list获得5的所有可能组合。 从这里我们可以使用filter ,只返回其总ItemCost小于或等于6返回组合。 最后我们按哪个组排序的ItemValue总数最多,我们取最大的一个是l2[-1]我们可以使用reverse = True然后它将是l2[0]

来自itertools导入组合

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)) 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM