【问题标题】:Lookup values from itemgetter in a dict从字典中的 itemgetter 查找值
【发布时间】:2018-06-09 22:32:03
【问题描述】:

我有一个要排序的元组列表。元组包含字符串:

connectionsList = [('C', 'B'), ('A', 'C'), ('D', 'B'), ('C','D')]

元组中的字符串具有存储在字典中的数值:

valuesDict = {'A':3, 'B':5, 'C':1, 'D':2}

我想做的是按元组字典中值的总和对列表进行排序。这个玩具示例的期望输出是:

[(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: operator.itemgetter(0) 的字典错误。

如何根据dict 中的值创建排序?

【问题讨论】:

  • sorted(connectionsList, key=lambda x: sum([valuesDict[y] for y in x]))?
  • 不过,您将不得不担心使用不存在的键进行索引。

标签: python sorting dictionary tuples


【解决方案1】:

不要使用itemgetter 实例;你需要打电话给他们,但他们在这里太过分了。

只需使用传递给lambdakey 值直接访问字典。它是一个元组,所以添加索引:

sortedView = sorted(connectionsList, key=lambda k: valuesDict[k[0]] + valuesDict[k[1]])

key 参数必须是一个可调用对象,它接受一个参数(正在排序的项目之一),并返回您实际排序的值。 itemgetter() 根据您调用它的对象的索引返回结果; itemgetter(0)(some_tuple) 将返回传入元组的第一个元素。

lambda 可以做同样的事情,在上述解决方案中,lambda 返回给定元组的所需总和。

演示:

>>> 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() 对象;元组已按0, 1 顺序提供,因此您将获得相同的排序顺序无需使用排序键。

【讨论】:

    【解决方案2】:

    如果您想使用itemgetter 查找valuesDictsum 中的键,则必须执行以下操作:

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

    注意,当lambdas 变得更复杂时,我通常更喜欢普通的def 函数,但这是个人喜好问题。在这种情况下,很容易将它们翻译成lambdas。

    【讨论】:

      【解决方案3】:

      你可以试试这样的:

      首先在列表中收集 sum 和 tuple:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-30
        • 2013-10-23
        • 1970-01-01
        • 1970-01-01
        • 2011-12-01
        • 1970-01-01
        • 2023-03-17
        • 2014-03-14
        相关资源
        最近更新 更多