在Python字典中查找最大键

5

常规:

我需要帮助找到一种在Python中获取多维字典中前 N 个最大值的方法。例如:

 things = {
          "car": { "weight": 100 },
          "apple": { "weight": 1 },
          "spanner": { "weight": 10 } 
          }

在这种情况下,我想要在字典中找到权重最高的两个项目,具体来说是这些项目的键。因此,在这种情况下,它应该返回["car", "spanner"]

实际问题:

注意:这是我第一次尝试遗传算法,所以可能我做得不正确。完全不正确。

作为一个英国人,我正在寻找我能想象到的最好的茶杯,因此我编写了一个Python程序,生成10个随机的茶杯,然后使用自然选择找出其中前5个,依此类推。

一杯茶被建模为一个Python字典,有5个键:

{
 "brew_time": Some Number,
 "milk": Some Number,
 "sweeteners": Some Number,
 "fitness": Some Number (This is what I'm interested in),
 "name": Some randomly generated name (Doesn't really matter)
}

我的程序生成的一杯茶看起来会像这样:
{'brew_time': 2.0, 'milk': 0.5, 'sweeteners': 3.0, 'name': 'bold cup', 'fitness': 0}

然后它会生成10杯茶,存储在teas变量中。以下是该输出的示例:

{0: {'brew_time': 2.0, 'milk': 0.4, 'sweeteners': 1.0, 'name': 'unafraid brew', 'fitness': 0}, 1: {'brew_time': 3.0, 'milk': 0.5, 'sweeteners': 3.0, 'name': 'fire-eating blend', 'fitness': 0}, 2: {'brew_time': 2.0, 'milk': 0.6, 'sweeteners': 2.0, 'name': 'fearless drink', 'fitness': 0}, 3: {'brew_time': 2.0, 'milk': 0.9, 'sweeteners': 3.0, 'name': 'fire-eating blend', 'fitness': 0}, 4: {'brew_time': 2.0, 'milk': 0.8, 'sweeteners': 2.0, 'name': 'fire-eating cuppa', 'fitness': 0}, 5: {'brew_time': 3.0, 'milk': 0.3, 'sweeteners': 1.0, 'name': 'fire-eating drink', 'fitness': 0}, 6: {'brew_time': 4.0, 'milk': 0.7, 'sweeteners': 2.0, 'name': 'dauntless medley', 'fitness': 0}, 7: {'brew_time': 3.0, 'milk': 0.3, 'sweeteners': 2.0, 'name': 'dauntless cuppa', 'fitness': 0}, 8: {'brew_time': 3.0, 'milk': 0.9, 'sweeteners': 2.0, 'name': 'epic drink', 'fitness': 0}, 9: {'brew_time': 2.0, 'milk': 0.4, 'sweeteners': 2.0, 'name': 'gusty drink', 'fitness': 0}}

我现在正在尝试编写一个名为selection()的函数,它将从字典中删除5种最不适合的茶叶。(一种茶叶的适应性由我设置,使用rank_tea()函数,该函数接受一个数组并设置所有茶叶的适应性,这是一个介于0-1之间的数字,表示茶叶的质量)

这是我目前的代码,但它不起作用:

def selection():
    teaCopy = teas.copy()
    fitnesses = []
    for i in range(0, len(teaCopy)):
        fitnesses.append(teas[i]["fitness"])

    print(fitnesses)

    max_fitnesses_indicies = sorted(range(len(fitnesses)), key=lambda x: fitnesses[x])
    print(max_fitnesses_indicies)

    len_array = []
    print(len_array)
    for i in range(0, len(teas)):
        len_array.append(i)

    to_be_del = list( set(max_fitnesses_indicies) - set(len_array) )
    print(to_be_del)
这是完整的代码。 很抱歉问题有点长,我只是不想遗漏任何内容。任何帮助都将不胜感激。

1
你得到了什么输出?有什么不起作用的地方吗? - Leon Z.
2
你的“实际问题”似乎与原问题无关,只会让读者感到困惑。我建议你构建一个最小可行示例。 - DYZ
StackOverflow主要用于修复错误。也许您应该考虑使用Code Review?此外,对于这个特定的问题,遗传算法似乎有些过度设计,因为您可以在单次遍历中找到最大值,弹出它,然后再进行一次遍历以找到下一个最大值。或者更一般地说,这是一个排序字典的问题。 - Maksim Kneller
了解如何创建一个 [mcve]。 - Peter Wood
1个回答

2
您可以简单地使用以下方法:
>>> sorted(things.keys(),key=lambda x:things[x]['weight'],reverse=True)
['car', 'spanner', 'apple']

获取按重量排序的项目列表(在此处反向排序,使更重的物品首先排序)。因此,如果您调用:
>>> sorted(things.keys(),key=lambda x:things[x]['weight'],reverse=True)[:2]
['car', 'spanner']

当你需要获取最大的两个值时,可以使用该方法。但是它的时间复杂度为O(n log n)。如果你想获取的值的数量k比总数小很多,你可以使用heapq

from heapq import nlargest

result = nlargest(k,things.keys(),key=lambda x:things[x]['weight'])

据我所知,这将以O(n log k)的速度运行(其中k是您想要选择的项目数量)。

然后只需截断列表? - Olly Britton
@OllyBritton:第二个代码片段已经使用[0:2]截取了列表。最后一个代码片段永远不会生成比k(第一个参数)更多的值,因此在这里您可以节省一些计算工作。 - Willem Van Onsem
[key for key, value in sorted(things.items(), key=lambda key, value: value['weight'], reverse=True)] 由于没有字典查找,因此会更快。 - Peter Wood
@PeterWood:我不知道那是否正确。虽然可以节省查找时间,但是你需要额外的元组打包/解包和一个额外的列表推导式。我并不确定哪种方法会显著优于另一种方法。 - Willem Van Onsem
@PeterWood:如果我没记错的话,Python也有一个小的轻量级元组缓存,因此它将首先检查某个特定的元组是否已经存在,这也是一种查找(但是在解释器中硬编码,因此更快)。尽管如此,它仍然需要一些时间。 - Willem Van Onsem
2
根据 %timeit,Willem 的表达式在一个包含 100 个项目的列表上运行速度比你的快约 20%。 - DYZ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接