从两个列表创建一个字典,但保留最小值

3

我正在使用一个字典,遇到了问题。假设我有两个列表需要创建一个字典,我知道可以使用zip函数来实现这一点,但问题是,我用于作为键(list1)的列表中有类似的元组。这仅仅是一个例子,列表中可能有更多的元素,但是两个列表的len总是相同的。

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = dict(zip(list1, list2))

print(mydict)

输出:

{(3, 2): 68, (2, 4): 29, (4, 3): 59, (4, 2): 3}

我知道键是唯一的,如果两个键相同,关联的值将是最后一个出现的。但我需要的是,如果两个键相同,则相关的值需要是最小的。例如,在list1中,我有两个重复的元组(2,4),分别关联的值为34和29,因此在创建字典时,我需要保留29,并且另一个重复的元组是(4,3),其值为29和59,如果创建字典,则希望值为29,而不是59。 我的期望输出结果:
{(3, 2): 68, (2, 4): 29, (4, 3): 29, (4, 2): 3}

有什么方法可以实现这个吗?非常感谢您的帮助!谢谢!
5个回答

4

从开始

keys = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]
values = [68, 34, 29, 29, 3, 59]

按值排序键-值对,按降序排列,然后根据此构建字典:
>>> dict(sorted(zip(keys, values), key=lambda x: -x[1]))
{(3, 2): 68, (4, 3): 29, (2, 4): 29, (4, 2): 3}

这种方法和你现有的dict(zip())结合起来的思路是相同的,但是在构建字典之前重新排列值,因此具有较低值的条目出现在后面。 因此,键的最小值最后出现。


当然,你不需要在一行中完成所有操作。 - Karl Knechtel
我的意思是太棒了!一行代码就能搞定,非常感谢! - Carlos Eduardo Corpus

3

一种方法是将条目排序,使最小值出现在列表的最后:

def get_value(pair): return pair[1]

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = dict(sorted(zip(list1, list2), key=get_value, reverse=True))

2

一种解决方案是逐步填充mydict

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = {}
for k,v in zip(list1,list2):
    if k in mydict:
        mydict[k] = min(mydict[k],v)
    else:
        mydict[k] = v

print(mydict)

如果需要,必须有一个简单的解决方案

关于IT技术方面的问题

2

不要试图去写一个复杂、晦涩难懂的一行代码或者列表推导式,使用简单的for循环就足以满足需求并保持可读性。我的建议是像下面这样:

def merge_lists(list1, list2):
    mydict = {}
    for k, v in zip(list1,list2):
        if (k not in mydict) or (mydict[k] > v):
            mydict[k] = v
    return mydict

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = merge_lists(list1, list2)

print(mydict)

# mydict = {(3, 2): 68, (2, 4): 29, (4, 3): 29, (4, 2): 3}

如果你想更深入地使用它,一些进一步的想法是对列表2进行排序,并同时移动列表1的索引。然后,使用这种结构,如果在列表1中出现重复的元素,那么你就知道它必须是第二个出现的。虽然这种方法不会带来任何性能提升或其他好处,但它是一种替代方案。

我赞成不试图将其强制转换为一行代码,但是你为什么要使用 for i in range(len()) 而不是只使用 for k,v in zip(list1,list2)?这将大大简化循环的内容。同时,你可以使用条件 if (k not in mydict) or (mydict[k] > v):,这样就不需要嵌套的 if 语句了。 - Tadhg McDonald-Jensen
1
@TadhgMcDonald-Jensen 你说得对,那样会更简洁(最近一直在写C语言;)),感谢你的建议。我进行了编辑。 - Andrew Holmgren

1
from operator import itergetter
from itertools import groupby

pairs = sorted(zip(list1, list2))
minima = {
    key: min(value for _, value in group)
    for key, group in groupby(sorted(pairs), itemgetter(0))
}

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