我有一个我正在尝试排序的元组列表。元组包含字符串:
connectionsList = [('C', 'B'), ('A', 'C'), ('D', 'B'), ('C','D')]
元组中的字符串具有存储在dict中的数值:
valuesDict = {'A':3, 'B':5, 'C':1, 'D':2}
我想要做的是按照元组dict中值的总和对列表进行排序。这个玩具示例的所需输出将是:
[(C,D), (A,C), (C,B), (D,B)]
的总和为:
[3, 4, 6, 7]
使用itemgetter,我可以按位置按字母顺序排序:
sortedView = sorted(connectionsList, key=itemgetter(0,1))
但是,我在查找dict中itemgetter的值时遇到问题。运行这个:
sortedView = sorted(connectionsList, key=valuesDict[itemgetter(0)] + valuesDict[itemgetter(1)])
给出 KeyError的dict错误:operator.itemgetter(0)。
如何根据dict中的值创建排序?
答案 0 :(得分:4)
不要使用itemgetter
个实例;你需要打电话给他们,但他们在这里有点过分。
只需使用传递到key
的{{1}}值直接访问字典即可。它是一个元组,所以添加索引:
lambda
sortedView = sorted(connectionsList, key=lambda k: valuesDict[k[0]] + valuesDict[k[1]])
参数必须是可调用对象,它接受一个参数(其中一个项目正在排序),并返回您实际排序的值。 key
根据您调用它的对象的索引返回结果; itemgetter()
将返回传入的元组中的第一个元素。
lambda也可以这样做,在上面的解决方案中,lambda返回给定元组的所需总和。
演示:
itemgetter(0)(some_tuple)
您还可以将您的元组视为任意长度的序列。如果您还考虑了元组中并非所有值都是>>> connectionsList = [('C', 'B'), ('A', 'C'), ('D', 'B'), ('C','D')]
>>> valuesDict = {'A':3, 'B':5, 'C':1, 'D':2}
>>> sorted(connectionsList, key=lambda k: valuesDict[k[0]] + valuesDict[k[1]])
[('C', 'D'), ('A', 'C'), ('C', 'B'), ('D', 'B')]
映射的有效键(取而代之的是valuesDict
)的可能性,您还可以获得以下解决方案:
0
这更通用,更健壮。
您也不需要按字母顺序使用sortedView = sorted(connectionsList, key=lambda k: sum(valuesDict.get(v, 0) for v in k))
对象;元组已经按itemgetter()
顺序提供,因此您可以使用排序键获得相同的排序顺序,而无需。
答案 1 :(得分:2)
如果您想使用valuesDict
在sum
和itemgetter
中查找密钥,则必须执行以下操作:
>>> from operator import itemgetter
>>> connectionsList = [('C', 'B'), ('A', 'C'), ('D', 'B'), ('C','D')]
>>> valuesDict = {'A':3, 'B':5, 'C':1, 'D':2}
>>> idx = 0
>>> sum(itemgetter(*itemgetter(0, 1)(connectionsList[idx]))(valuesDict))
6
connectionsList[idx]
是将传递给key
函数的当前元素。因此,您需要对此进行转换,以便实际的键功能仅需要当前元素作为参数:
>>> def keyfunc(cur_element):
... return sum(itemgetter(*itemgetter(0, 1)(cur_element))(valuesDict))
>>> sorted(connectionsList, key=keyfunc)
[('C', 'D'), ('A', 'C'), ('C', 'B'), ('D', 'B')]
然而,与没有itemgetter
的解决方案相比,这并不是真的可读:
>>> def keyfun(cur_element):
... i1, i2 = cur_element
... return valuesDict[i1] + valuesDict[i2]
>>> sorted(connectionsList, key=keyfunc)
[('C', 'D'), ('A', 'C'), ('C', 'B'), ('D', 'B')]
所以在这种情况下你可能不应该使用itemgetter
,因为它涉及更多的函数调用,结果函数不是那么好。
如果valuesDict
字典中可能缺少部分密钥,则应将[]
循环替换为get
次调用:
>>> def keyfun(cur_element):
... i1, i2 = cur_element
... return valuesDict.get(i1, 0) + valuesDict.get(i2, 0)
>>> sorted(connectionsList, key=keyfunc)
[('C', 'D'), ('A', 'C'), ('C', 'B'), ('D', 'B')]
注意我通常更喜欢正常def
函数而不是lambda
s当它们变得更复杂时,但这是一个品味问题。在这种情况下,很容易将它们翻译为lambda
s。
答案 2 :(得分:0)
您可以尝试这样的事情:
首先在列表中收集总和和元组:
connectionsList = [('C', 'B'), ('A', 'C'), ('D', 'B'), ('C','D')]
valuesDict = {'A':3, 'B':5, 'C':1, 'D':2}
tuple_sum=[]
for i in connectionsList:
tuple_sum.append((valuesDict.get(i[0])+valuesDict.get(i[1]),i))
它会给出:
[(6, ('C', 'B')), (4, ('A', 'C')), (7, ('D', 'B')), (3, ('C', 'D'))]
现在对它进行排序并仅采用嵌套元组:
print(list(map(lambda x:x[1],sorted(tuple_sum))))
输出:
[('C', 'D'), ('A', 'C'), ('C', 'B'), ('D', 'B')]