【问题标题】:Is there an efficient way of creating a list of tuples using a range?有没有使用范围创建元组列表的有效方法?
【发布时间】:2018-05-28 10:29:44
【问题描述】:

我正在寻找一种有效的方法来将(20,24) 之类的数字范围与{'a': 'b'} 之类的另一个对象组合起来,

[(20, {'a': 'b'}), (21, {'a': 'b'}), (22, {'a': 'b'}), (23, {'a': 'b'})]

如果我有一个像[20, 21, 22, 23] 这样的数字列表,我知道遍历列表是可行的方法。但在这里我有一系列数字。所以可能有一种方法可以更优雅地将范围元素包装在元组中。

这是我实现这一目标的尝试:

min = 20
max = 23
data = {"a": "b"}
result = []
for i in range(min, max + 1):
    result.append((i, data))
print(result)

我只是想知道是否有更好的方法来做到这一点。

【问题讨论】:

  • [(x, data) for x in range(20, 24)]?请记住,您只是在复制参考。改变一个字典,它们都会改变。
  • 这很好,但“更好”是值得怀疑的 ;)
  • 请记住,在所有这些情况下,更改data["a"] = "z" 将影响result 的每个元素。

标签: python python-3.x list tuples


【解决方案1】:

确实,任何附加到空列表的 for 循环都可以转换为列表推导式。

l = []
for x in range(20, 24):
    l.append((x, data))

或者,

l = [(x, data) for x in range(20, 24)]

然而!请注意,您得到的是这个 -

for i in l:
     print(id(i[1]))

4835204232
4835204232
4835204232
4835204232

同一对象被引用复制多次。这是可变对象的一个​​问题,因为如果您更改一个对象,它们都会反映该更改。因此,我建议您在每一步都复制您的数据。您可以使用内置的dict.copy 函数,也可以使用copy 模块中的函数。在前一种情况下,只完成了一个浅拷贝,所以如果你有一个嵌套结构,那不是一个好主意。

不管怎样,我就是这样做的——

import copy
l = [(x, copy.deepcopy(data)) for x in range(20, 24)]

如果您的字典结构不复杂(例如 - {'a' : {'b' : 'c'}}),我上面提到的 dict.copy 方法有效 -

l = [(x, data.copy()) for x in range(20, 24)]

【讨论】:

  • 不应该是print(id(i[1]))(例如i而不是l)?
  • @Tjorriemorrie 确实如此。这是一个复制粘贴错误。感谢您指出。
【解决方案2】:

只需使用列表推导:

mins = 20
maxs = 23
data = {'a': 'b'}
print([(x, data) for x in range(mins, maxs + 1)])
# [(20, {'a': 'b'}), (21, {'a': 'b'}), (22, {'a': 'b'}), (23, {'a': 'b'})]

或者你也可以在这里使用map()

print(list(map(lambda x: (x, data), range(mins, maxs + 1))))
# [(20, {'a': 'b'}), (21, {'a': 'b'}), (22, {'a': 'b'}), (23, {'a': 'b'})]

注意:在您的版本中,您使用maxmin 作为变量名。这不是一个好主意,因为它们已经是内置函数。请改用不同的变量名称。

此外,正如其他人所提到的,您希望重复的字典在所有元组中都是内存中的同一个对象。您可以使用@cᴏʟᴅsᴘᴇᴇᴅ 的信息性答案解决此问题。

【讨论】:

    【解决方案3】:

    itertools.repeat 提供了一种干净的方式来执行此操作。

    >>> from itertools import repeat
    >>> min = 20
    >>> max = 23
    >>> data = {"a": "b"}
    >>> 
    >>> list(zip(range(min, max+1), repeat(data)))
    [(20, {'a': 'b'}), (21, {'a': 'b'}), (22, {'a': 'b'}), (23, {'a': 'b'})]
    

    请注意,字典{'a':'b'} - 或您repeat 的每个对象 - 使用这种方法在每个元组中将是内存中的相同对象。

    【讨论】:

      【解决方案4】:

      一种有趣的方式是使用 zip,即

      mini = 20
      maxi = 24
      data = {'a':'b'}
      l = range(mini,maxi)
      
      list(zip(l,[data]*len(l)))
      
      [(20, {'a': 'b'}), (21, {'a': 'b'}), (22, {'a': 'b'}), (23, {'a': 'b'})]
      

      【讨论】:

      • 请注意,这仍然受到我的回答中概述的问题的影响。尽管如此,还是因为开箱即用而受到支持。
      • 是的,是的,我明白了,删除了评论
      • 您可以,但是使用copy 消除此问题,因此一旦您解决此问题,这仍然是一个有效的答案。
      【解决方案5】:

      总有比追加到空列表更好的方法。您可以转换任何形式的表达式

      result = []
      for i in iterable:
          result.append(something)
      

      列表理解

      result = [something for i in iterable]
      

      这使您的代码的核心非常简单。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多