【问题标题】:Appending a list to a list in a loop (Python)将列表附加到循环中的列表(Python)
【发布时间】:2021-10-31 05:52:18
【问题描述】:

我有一个带有值的 Python 列表,比如:

a = [[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]]

我想在循环中将一个新列表“b”附加到列表“a”中。

b = [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]

结果应如下所示(将 'b' 一次添加到 'a' 时):

[[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]

现在,我想将列表b 追加N 次到列表aab 都有形状 (4,3) 然后结果应该有形状:(N+1,4,3)

我该怎么做?

【问题讨论】:

  • 要记住的一点是列表是可变的。对于您的用例,如果列表字面上是 [a, b, b, b] 可以吗? (如果我稍后在代码中执行b[1][3] = "PASTA",是否可以将自身传播到您的结果数组中?(例如array[2][1][3] 将给出"PASTA"
  • 你可能想要一个 numpy.array,而不是原生 Python 列表!

标签: python list append


【解决方案1】:

本机 Python 列表不会按照您在此处所描述的一些 cmets 的方式运行,因此如果您可以使用第 3 方库,请考虑 NumPy,它的行为更像矩阵您期望的值,然后可以转换回 Python 列表

设置

>>> a = [[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]]
>>> b = [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]

垂直复制b

  • np.tile() 的第二个参数描述了每个维度中的复制
  • .reshape() 将其准备为 3 维数组
>>> import numpy as np
>>> b_tiled = np.tile(np.array(b), (4,1)).reshape(4,4,3)
>>> b_tiled
array([[[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]],

       [[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]],

       [[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]],

       [[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]]])

ab_tiled收集到同一个数组中

注意a 应重新整形或[a] 以匹配b_tiled 的形状

>>> np.vstack((np.array([a]), b_tiled))
array([[[0, 0, 0],
        [1, 0, 1],
        [1, 1, 0],
        [0, 1, 1]],

       [[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]],

       [[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]],

       [[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]],

       [[2, 1, 0],
        [3, 0, 1],
        [4, 1, 0],
        [2, 1, 1]]])

.tolist()

您可以使用.tolist() 再次创建一个原生 Python 列表,但作为一个 numpy 数组对您来说可能更方便

>>> np.vstack((np.array([a]), b_tiled)).tolist()
[[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]

【讨论】:

  • 看起来更干净,因为你必须导入一个库,例如复制,它是更好的解决方案。我看到的唯一缺点是 numpy 比副本重得多,例如。 G。对于您想要创建可执行文件的不太可能的情况。无论如何,可能是最好的解决方案!
  • 由于np.array() 会正确复制其输入,您还可以将代码缩短为np.array([a]+[b]*5)
  • 小心,你的答案有形状 (20,3) 而不是 (5,4,3) 我相信 OP 想要的。
  • 这可能是最干净的,因为我花了一点时间试图找出一种舒适的方式来获得他们看起来想要的东西
  • @joanis 另一个重塑将纠正这一点!
【解决方案2】:

将我对这次讨论的贡献总结为一个实际的答案,总结我认为的两个最佳解决方案:

1 使用 NumPy 数组

从@Andreas 的解决方案开始,但遵循@ti7 的引导并将结果包装到一个numpy 数组中,该数组可以正确管理内存:

result = np.array([a] + [b] * 5)

此解决方案将结果带入更多可用和通用的 NumPy 数组中。

2 使用深拷贝

从@Andreas 的解决方案开始,添加一个深拷贝,这样结果就不会将数组的各个部分混在一起:

import copy
result = [a] + [copy.deepcopy(b) for _ in range(5)]

此解决方案将结果保留为标准 Python 列表列表。

感谢@ti7 注意到深层复制必须通过b 的实例而不是结果完成,因为deepcopy 不会破坏其输入内部的别名;并感谢@Andreas 从 cmets 组装这行代码。

警告:由于a 未在此处进行深度复制,result[0]a 的别名,对其中任何一个的更改都会同时更改两者。深拷贝a 也可以避免这种情况。

【讨论】:

    【解决方案3】:

    添加列表并乘以第二个列表:

    l = [a] + [b]*5
    
    [[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]],
     [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
     [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
     [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
     [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
     [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]
    

    如果您想稍后修改列表值,请注意您实际上引用了 5 倍的 SAME 列表(如 @ti7 所述),这意味着如果您更改列表 b 中的一个值,您将全部更改,如下所示:

    l[1][1][1] = "foo"
    
    [[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]]
    [[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
    [[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
    [[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
    [[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
    [[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
    

    为了避免这种使用(如 @joanis 所述)

    l = [a] + [copy.deepcopy(b) for _ in range(5)]
    

    【讨论】:

    • 这并不直接起作用,因为许多成员都指的是同一个成员!自己试试c = [a] + [b]*5c[1][1][1] = "foo"
    • 为了保护结果不被共享引用,我会使用copy.deepcopy:import copy,c = copy.deepcopy([a] + [b]*5)
    • @ti7 和 joanis 根据您的 cmets 更新了答案。非常感谢您指出这一点!
    • 每个副本都需要做(具体是列表乘法比较麻烦)
    • @joanis 不幸的是,这不起作用,因为 ti7 指出您必须单独深复制每个列表,如更新的答案所示。
    【解决方案4】:

    [a+b*5] 这将创建

    [[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-13
      • 2022-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      相关资源
      最近更新 更多