【问题标题】:Replacing an element in a list with multiple elements用多个元素替换列表中的一个元素
【发布时间】:2017-07-05 19:13:29
【问题描述】:

我正在尝试修改包含两个列表的列表。对于两个内部列表中的每一个,我都会执行一些操作并将它们“拆分”为新列表。
这是我正在尝试做的一个简单示例:

[['a', 'b'], ['c', 'd']]  -->  [['a'], ['b'], ['c', 'd']]

目前,我的算法将 ['a', 'b'] 传递给一个函数,该函数确定是否应将其拆分为 [['a'], ['b']](例如,基于它们的相关性)。该函数返回[['a'], ['b']],它告诉我['a', 'b'] 应该被拆分,或者返回['a', 'b'](原始列表),这表明它不应该被拆分。

目前我有这样的事情:

blist = [['a', 'b'], ['c', 'd']]   #big list
slist =  [['a'], ['b']]            #small list returned by function

nlist = [items for i in xrange(len(blist)) for items in (slist if i==0 else blist[i])]

这会产生[['a'], ['b'], 'c', 'd'],而不是所需的输出[['a'], ['b'], ['c', 'd']],后者不会改变原始列表中的第二个列表。我理解为什么会发生这种情况——在这种情况下,我的第二个循环也适用于 blist[1],但我不确定如何解决它,因为我不完全理解列表理解。

首选“pythonic”解决方案。 任何反馈将不胜感激,谢谢!

编辑:正如标题所示,我正在尝试用['a'], ['b'] '替换'['a', 'b']。所以我希望'位置'是相同的,['a'], ['b'] 出现在['c', 'd'] 之前的原始列表中

结果 感谢 Christian、Paul 和 schwobaseggl 的解决方案!他们都工作:)

【问题讨论】:

  • 你在自相矛盾。您是将项目传递给函数还是使用嵌套列表理解?无论如何,如果您不了解列表推导,为什么不使用简单的 for 循环,直到您了解?我愿意。
  • 对不起,我的意思是该函数用于帮助确定列表是否被拆分,嵌套列表理解执行更改/拆分
  • @hop 我相信我了解简单的 for 循环。我想更熟悉列表推导并有更好的理解。只是想练习一下。另外,通过“我会”,您是否建议仅使用简单的 for 循环有助于理解列表理解?我知道它们有相似之处,但是就像在我的示例中一样,列表理解似乎与不同顺序的语句更加紧凑。您能否详细说明两者之间的关系?

标签: python python-2.7 list list-comprehension


【解决方案1】:

试试

...  else [blist[i]])]

创建列表列表。

【讨论】:

    【解决方案2】:

    你可以使用切片赋值:

    >> l1 = [[1, 2], [3, 4]]
    >>> l2 = [[1], [2]]
    >>> l1[0:1] = l2
    >>> l1
    [[1], [2], [3, 4]]
    

    这改变了l1,所以如果你想保留它,请先复制一份。

    另一种不会改变l1 的方式是加法:

    >> l1 = [[1, 2], [3, 4]]
    >>> l3 = l2 + l1[1:]
    >>> l3
    [[1], [2], [3, 4]]
    

    【讨论】:

    • 不,应该将l2 的元素1 和2 代替当前位于l1 位置0 的元素[1, 2],换句话说,它失去了括号 1 和 2。
    • 进行所谓的分片复制,应该或多或少等价于.copy()。请注意,这在 numpy 中有所不同,其中切片不会创建副本而是创建视图。
    • 您没有更改l1 或者更确切地说是绑定到名称l1 的对象,您正在将一个新对象(您的列表理解的产物)绑定到l1。列表推导确实会生成一个新列表,因此它需要为此分配空间。我现在不是真的,但我猜列表推导非常有效,也就是说,如果你只更改一个位并复制所有其余部分,那么切片分配可能是更好的选择。实际上,我在答案右侧使用的切片副本不是必需的。抱歉,我会解决的。
    • 我认为基本逻辑是l1[0:1]给出了l1这部分的副本作为列表。所以它也应该反过来工作。如果您分配给l1[0:1],它应该接受一个列表,制作一份副本并将列表放在完全相同的位置。请注意,这会改变列表的长度。
    • 我认为如果您使用赋值语法,则不会复制此位。为什么应该有?不需要该位。但是,由于您可能会更改列表的长度,因此可能需要进行一些相对昂贵的重组。我不太了解内部结构,无法在这里更具体。但是,只有当您处理可能包含 100,000 个或更多元素的大型列表或制作大量列表或多次循环它们时,这些考虑才真正值得。对于花园品种列表,您甚至不会注意到。
    【解决方案3】:

    假设您具有决定是否拆分项目的上述功能:

    def munch(item):
        if item[0] == 'a': # split
            return [[item[0]], [item[1]]]
        return [item] # don't split
    

    您可以在简单的 for 循环中使用它。

    nlist = []
    for item in blist:
        nlist.extend(munch(item))
    

    “Pythonic”是任何易于阅读和理解的东西。不要仅仅因为可以就使用列表推导式。

    【讨论】:

    • 您能否简要解释一下 munch 在这里的作用?一个例子真的很有帮助。谢谢!
    • @AsheKetchum:您可以轻松地将代码放入 Python 命令行并自己尝试。
    【解决方案4】:

    您可以更改拆分函数以返回结构上足够的列表。然后你可以使用理解:

    def split_or_not(l):
      if condition: # split
        return [l[:1], l[1:]]
      return [l]  # wrap in extra list
    
    # using map
    nlist = [x for sub_l in map(split_or_not, blist) for x in sub_l]
    # or nested comprehension
    nlist = [x for sub_l in (split_or_not(l) for l in blist) for x in sub_l]
    

    【讨论】:

    • 这是一个非常好的观点!我投了赞成票,但它没有显示,因为我的声望不到 15 哈哈。我将修改返回对象结构。此外,当返回[l] 而不是l 时会发生什么?将l 放入列表是否需要额外的时间?
    • 新列表只保存对列表的引用,开销应该可以忽略不计!
    • 如果使用list.extend() 和普通的for循环,可以大大降低代码的复杂度。应该避免嵌套列表推导(说到“pythonic”)。
    • @hop 你有最后一条声明的来源吗?据我所知,嵌套推导与其他方法相比表现更好,参见例如http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python
    • @hop 虽然我(大部分)同意可读性 > 性能,但我认为这个答案中的任何示例都没有可读性差。我承认习惯它有什么。与它有关,但比 Pythonicity 更多的是品味问题 ;)
    猜你喜欢
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 2018-07-23
    • 2021-05-19
    • 2017-06-14
    • 1970-01-01
    • 2021-09-21
    • 2019-06-27
    相关资源
    最近更新 更多