【问题标题】:Converting a single ordered list in python to a dictionary, pythonically将python中的单个有序列表转换为字典,pythonically
【发布时间】:2009-10-28 20:06:01
【问题描述】:

我似乎找不到从 t 开始并导致 s 的优雅方式。

>>>t = ['a',2,'b',3,'c',4]
#magic
>>>print s
{'a': 2, 'c': 4, 'b': 3}

我想出的解决方案似乎不够优雅:

s = dict()
for i in xrange(0, len(t),2): s[t[i]]=t[i+1]
# or something fancy with slices that I haven't figured out yet

这显然很容易解决,但是,似乎还有更好的方法。有吗?

【问题讨论】:

    标签: list dictionary python itertools


    【解决方案1】:

    我会使用itertools,但是,如果您认为这很复杂(正如您在评论中暗示的那样),那么也许:

    def twobytwo(t):
      it = iter(t)
      for x in it:
        yield x, next(it)
    
    d = dict(twobytwo(t))
    

    或等效,然后再次返回 itertools,

    def twobytwo(t):
      a, b = itertools.tee(iter(t))
      next(b)
      return itertools.izip(a, b)
    
    d = dict(twobytwo(t))
    

    或者,如果您坚持要内联,则以适合季节的“不给糖就捣蛋”的心情:

    d = dict((x, next(it)) for it in (iter(t),) for x in it)
    

    我,我认为这是一种技巧,但有些人可能会觉得这是一种享受。 IOW,我觉得这种事情很可怕,但显然在美国每年的这个时候事情都是应该;-)。

    基本上,问题归结为“我如何一次遍历列表 2 个项目”,因为 dict 非常乐意将 2 元组序列放入字典中。我在这里展示的所有解决方案都确保只占用O(1) 额外空间(在空间之外,显然O(N),这是输入列表和输出字典所需要的,当然)。

    docs 中建议的方法(每个人都应该熟悉那个页面,itertool recipes)是那个页面上的函数pairwise,这基本上是我在这里建议的第二个。我确实认为每个 site-packages 目录都应该包含一个带有这些配方的 iterutils.py 文件(可惜这样的文件还不是 python 标准库的一部分!-)。

    【讨论】:

      【解决方案2】:

      Lukáš Lalinský's answer相同的想法,不同的成语:

      >>> dict(zip(*([iter(t)] * 2)))
      {'a': 2, 'c': 4, 'b': 3}
      

      这使用了dictzipiter 函数。与 Lukáš 的回答相比,它的优势在于它适用于任何可迭代对象。它是如何工作的:

      1. iter(t) 在列表 t 上创建一个迭代器。
      2. [iter(t)] * 2 创建一个包含两个元素的列表,它们引用同一个迭代器。
      3. zip 是一个函数,它接受两个可迭代对象并将它们的元素配对:第一个元素放在一起,第二个元素放在一起,等等,直到一个可迭代对象用完。
      4. zip(*([iter(t)] * 2)) 导致 t 上的相同迭代器作为 both 参数传递给 zip。因此,zip 将采用t 的第一个和第二个元素并将它们配对。然后是第三和第四。然后是第五和第六等等。
      5. dict 接受一个包含 (key, value) 对的可迭代对象,并从中创建一个字典。
      6. dict(zip(*([iter(t)] * 2))) 根据 OP 的要求创建字典。

      【讨论】:

      • 这(以及所有其他答案)似乎并不是特别优雅。有没有内置方式?
      • 没有我知道的单一功能,抱歉。
      【解决方案3】:

      效率不高,但如果您不需要它来处理非常大的列表:

      dict(zip(t[::2], t[1::2]))
      

      或者您使用生成器的版本:

      dict(t[i:i+2] for i in xrange(0, len(t), 2))
      

      【讨论】:

        【解决方案4】:

        伙计们,伙计们,使用 itertools。当列表变大时,您的低 RAM 用户会感谢您。

        >>> from itertools import izip, islice
        >>> t = ['a',2,'b',3,'c',4]
        >>> s = dict(izip(islice(t, 0, None, 2), islice(t, 1, None, 2)))
        >>> s
        {'a': 2, 'c': 4, 'b': 3}
        

        它可能看起来不漂亮,但它不会在内存中创建不必要的副本。

        【讨论】:

        • 确实在 Python 2 中应该使用itertools。然而,在 Python 3 中,zip 返回一个生成器。在这种情况下,dict(zip(*([iter(t)] * 2))) 也可以。
        • 由于原始问题使用print s 而不是print(s) 我假设是Python 2 :)
        • 这似乎比必要的复杂 - 但我很欣赏内存中副本的缺乏 =)
        【解决方案5】:

        使用stream 模块:

        >>> from stream import chop
        >>> t = ['a',2,'b',3,'c',4]
        >>> s = t >> chop(2) >> dict
        >>> s
        {'a': 2, 'c': 4, 'b': 3}
        

        应该注意的是,这个模块相当晦涩,并没有真正“遵守规则”,通常被认为是政治上正确的 Python。所以如果你只是学习 Python,请不要走这条路;坚持标准库中的内容。

        【讨论】:

          【解决方案6】:
          dict(zip(t[::2], t[1::2]))
          

          可能不是最有效的。在 python 3 中工作;您可能需要在 python 2.x 中导入 zip

          【讨论】:

          • zip 首次出现在 2.0 中,根据文档。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-02-10
          • 1970-01-01
          • 2015-07-23
          • 1970-01-01
          • 2016-09-14
          • 1970-01-01
          • 2021-07-01
          相关资源
          最近更新 更多