【问题标题】:How do I exchange keys with values in a dictionary?如何用字典中的值交换键?
【发布时间】:2010-11-08 10:20:47
【问题描述】:

我收到一个字典作为输入,并想返回一个字典,其键将是输入的值,其值将是相应的输入键。价值观是独一无二的。

例如,假设我的输入是:

a = dict()
a['one']=1
a['two']=2

我希望我的输出是:

{1: 'one', 2: 'two'}

为了澄清,我希望我的结果相当于以下内容:

res = dict()
res[1] = 'one'
res[2] = 'two'

有任何简洁的 Pythonic 方式来实现这一点吗?

【问题讨论】:

  • 如果您使用 Python 3,请参阅 stackoverflow.com/questions/1087694/… 以获得一个很好的答案
  • @Stephen:查看第二个投票最多的答案,它与您链接到的问题中被接受的答案相同。人群更喜欢另一个答案......
  • Python 不是 perl,python 不是 ruby​​。可读性很重要。稀疏比密集好。鉴于此,这些答案的所有方法都是糟糕的™;问题中的那个是最好的方法。

标签: python dictionary


【解决方案1】:

Python 2:

res = dict((v,k) for k,v in a.iteritems())

Python 3(感谢@erik):

res = dict((v,k) for k,v in a.items())

【讨论】:

  • 虽然这似乎是正确的,但添加对其工作原理的解释而不仅仅是代码真的很好。
  • 如果值不是唯一的怎么办?那么键应该是一个列表...例如: d = {'a':3, 'b': 2, 'c': 2} {v:k for k,v in d.iteritems()} { 2: 'b', 3: 'a'} 应该是 {2: ['b','c'], 3: 'a'}
  • @HananShteingart:OP 的问题陈述值是唯一的。请为您的案例创建一个单独的问题帖子(最好将其链接到此处以供其他人使用)。
  • python2 代码工作...但列表理解缺少[]。列表理解不需要[]
  • 两件事:1)如果您的原始值有重复值,它将覆盖以前的值,您最终会得到一个较短的字典; 2)如果“值”不是可散列的——比如数组——就会失败。
【解决方案2】:
new_dict = dict(zip(my_dict.values(), my_dict.keys()))

【讨论】:

  • 真的 values() 和 keys() 保证有相同的顺序吗?
  • 是的,来自python.org/dev/peps/pep-3106 规范暗示 .keys()、.values() 和 .items() 返回项目的顺序是相同的(就像在 Python 中一样2.x),因为顺序都是从 dict 迭代器派生的(这可能是任意的,但只要不修改 dict 就稳定)。但是这个答案需要调用 my_dict 两次(一次用于值,一次用于键)。也许这并不理想。
  • 是的,这个答案会遍历字典两次。 sunqiang 的答案更适合大型字典,因为它只需要一次迭代。
  • @Carl Meyer:同意,另外,他正在使用更适合大型数据集的 itertools。虽然我想知道最后的 dict() 调用是否也在流式传输,或者它是否首先组装了整个对列表
  • @CarlMeyer 另外对于 n > 1e6(或 1e9),内存使用量也会非常大......并且也会减慢很多速度。
【解决方案3】:

从 Python 2.7 开始,包括 3.0+,有一个可以说更短、更易读的版本:

>>> my_dict = {'x':1, 'y':2, 'z':3}
>>> {v: k for k, v in my_dict.items()}
{1: 'x', 2: 'y', 3: 'z'}

【讨论】:

    【解决方案4】:
    In [1]: my_dict = {'x':1, 'y':2, 'z':3}
    

    Python 3

    In [2]: dict((value, key) for key, value in my_dict.items())
    Out[2]: {1: 'x', 2: 'y', 3: 'z'}
    

    Python 2

    In [2]: dict((value, key) for key, value in my_dict.iteritems())
    Out[2]: {1: 'x', 2: 'y', 3: 'z'}
    

    【讨论】:

    • 不是在原始问题中,我只是好奇如果您在原始字典中有重复值然后使用此方法交换键/值会发生什么?
    • @Andre Miller:它需要最后一次出现的特定键:dict(((1,3),(1,2))) == {1:2}
    • 重复项将被最后遇到的重复项覆盖。
    • @Andre Miller:因为 d.items() 以任意顺序返回项目,所以您可以获得用于重复值的任意键。
    • 我认为它将采用它找到的最后一个键值对。这就像 a['x'] = 3。然后你设置 a['x'] = 4。
    【解决方案5】:

    您可以使用dict comprehensions:

    Python 3

    res = {v: k for k, v in a.items()}
    

    Python 2

    res = {v: k for k, v in a.iteritems()}
    

    已编辑:对于 Python 3,请使用 a.items() 而不是 a.iteritems()。关于它们之间的差异的讨论可以在 SO 上的iteritems in Python 找到。

    【讨论】:

      【解决方案6】:

      当前的主要答案假设值是唯一的,但情况并非总是如此。如果值不是唯一的怎么办?你会丢失信息! 例如:

      d = {'a':3, 'b': 2, 'c': 2} 
      {v:k for k,v in d.iteritems()} 
      

      返回{2: 'b', 3: 'a'}

      关于'c' 的信息被完全忽略了。 理想情况下,它应该类似于{2: ['b','c'], 3: ['a']}。这就是底层实现的作用。

      Python 2.x

      def reverse_non_unique_mapping(d):
          dinv = {}
          for k, v in d.iteritems():
              if v in dinv:
                  dinv[v].append(k)
              else:
                  dinv[v] = [k]
          return dinv
      

      Python 3.x

      def reverse_non_unique_mapping(d):
          dinv = {}
          for k, v in d.items():
              if v in dinv:
                  dinv[v].append(k)
              else:
                  dinv[v] = [k]
          return dinv
      

      【讨论】:

      • 这应该是正确的答案,因为它涵盖了更一般的情况
      • 谢谢你!我在使用其他解决方案时丢失了信息。
      【解决方案7】:

      你可以试试:

      Python 3

      d={'one':1,'two':2}
      d2=dict((value,key) for key,value in d.items())
      d2
        {'two': 2, 'one': 1}
      

      Python 2

      d={'one':1,'two':2}
      d2=dict((value,key) for key,value in d.iteritems())
      d2
        {'two': 2, 'one': 1}
      

      请注意,如果

      1. 多个键共享相同的值。例如{'one':1,'two':1}。新字典只能有一个键为 1 的项目。
      2. 一个或多个值是不可散列的。例如{'one':[1]}[1] 是有效值,但不是有效键。

      请参阅 python 邮件列表上的 this thread 以获取有关该主题的讨论。

      【讨论】:

      • 另外+1关于确保原始字典中的值是唯一的注释;否则你会在'reversed' dict中被覆盖......这(我只是发现这个是我的成本)可能会导致你的代码中出现棘手的错误!
      【解决方案8】:

      res = dict(zip(a.values(), a.keys()))

      【讨论】:

      • dict 不保证其 values() 和 keys() 将以相同的顺序返回元素。此外,keys()、values() 和 zip() 返回一个列表,其中一个迭代器就足够了。
      • @liori:你错了。 dict 保证它的 values() 和 keys() 将处于相同的顺序,如果您当然不修改调用 values() 和 keys() 之间的字典。文档在此处指出:(阅读“注释”部分:docs.python.org/library/stdtypes.html#dict.items)“如果在没有干预修改的情况下调用 items()、keys()、values()、iteritems()、iterkeys() 和 itervalues()到字典,列表将直接对应。”
      • 好吧,那我错了……我没查过在线文档。感谢您指出这一点。
      • 您可以使用迭代器 itertools.izip 而不是 zip 来提高这个答案的效率。
      • 还有 iterkeys 和 itervalues。但也可以使用 iteritems()
      【解决方案9】:
      new_dict = dict( (my_dict[k], k) for k in my_dict)
      

      甚至更好,但仅适用于 Python 3:

      new_dict = { my_dict[k]: k for k in my_dict}
      

      【讨论】:

      • 实际上 Dict Comprehensions (PEP 274) 也适用于 Python 2.7。
      【解决方案10】:

      扩展Ilya Prokin's response 的另一种方法是实际使用reversed 函数。

      dict(map(reversed, my_dict.items()))
      

      本质上,您的字典被迭代(使用.items()),其中每个项目都是一个键/值对,并且这些项目与reversed 函数交换。当 this 传递给 dict 构造函数时,它会将它们转换为您想要的值/键对。

      【讨论】:

        【解决方案11】:

        对哈维尔答案的改进建议:

        dict(zip(d.values(),d))
        

        您可以只写d 而不是d.keys(),因为如果您使用迭代器遍历字典,它将返回相关字典的键。

        例如。对于这种行为:

        d = {'a':1,'b':2}
        for k in d:
         k
        'a'
        'b'
        

        【讨论】:

          【解决方案12】:

          可以通过字典理解轻松完成:

          {d[i]:i for i in d}
          

          【讨论】:

          • 简洁。新 dict 的行为方式使得旧值的唯一键在新含义值中可能会丢失。
          【解决方案13】:
          dict(map(lambda x: x[::-1], YourDict.items()))
          

          .items() 返回(key, value) 的元组列表。 map() 遍历列表的元素并将lambda x:[::-1] 应用于其每个元素(元组)以反转它,因此每个元组在从映射中吐出的新列表中变为(value, key)。最后,dict() 从新列表中创建一个 dict。

          【讨论】:

          • .items() 返回一个元组列表(键、值)。 map() 遍历列表的元素并将lambda x:[::-1] 应用于其每个元素(元组)以将其反转,因此每个元组都成为从映射中吐出的新列表中的(值,键)。最后,dict() 从新列表中生成一个字典。
          【解决方案14】:

          Hanan 的答案是正确的,因为它涵盖了更一般的情况(其他答案对于不知道重复情况的人来说有点误导)。对 Hanan 的回答的改进是使用 setdefault:

          mydict = {1:a, 2:a, 3:b}   
          result = {}
          for i in mydict:  
             result.setdefault(mydict[i],[]).append(i)
          print(result)
          >>> result = {a:[1,2], b:[3]}
          

          【讨论】:

            【解决方案15】:

            使用循环:-

            newdict = {} #Will contain reversed key:value pairs.
            
            for key, value in zip(my_dict.keys(), my_dict.values()):
                # Operations on key/value can also be performed.
                newdict[value] = key
            

            【讨论】:

              【解决方案16】:

              如果您使用的是 Python3,则略有不同:

              res = dict((v,k) for k,v in a.items())
              

              【讨论】:

                【解决方案17】:

                添加就地解决方案:

                >>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
                >>> for k in list(d.keys()):
                ...     d[d.pop(k)] = k
                ... 
                >>> d
                {'two': 2, 'one': 1, 'four': 4, 'three': 3}
                

                在 Python3 中,使用list(d.keys()) 至关重要,因为dict.keys 返回键的视图。如果你使用的是 Python2,d.keys() 就足够了。

                【讨论】:

                  【解决方案18】:

                  我觉得这个版本最全面:

                  a = {1: '一', 2: '二'}

                  swapped_a = {value : key for key, value in a.items()}

                  打印(交换的_a)

                  输出: {'一':1,'二':2}

                  【讨论】:

                    【解决方案19】:

                    另一种选择(在我看来)不如其他一些答案那么易读:

                    new_dict = dict(zip(*list(zip(*old_dict.items()))[::-1]))

                    list(zip(*old_dict.items()))[::-1] 给出一个包含 2 个元组的列表,分别是 old_dict 的值和键。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-07-21
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多