【问题标题】:Replacing list item with contents of another list用另一个列表的内容替换列表项
【发布时间】:2013-02-19 16:49:45
【问题描述】:

类似于this question,但我不想用另一项替换一项,而是想用列表的内容替换任何出现的一项。

orig = [ 'a', 'b', 'c', 'd', 'c' ]
repl = [ 'x', 'y', 'z' ]
desired = [ 'a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z' ]

# these are all incorrect, or fail to compile
[ repl if x == 'c' else x for x in orig ]
[ [a for a in orig] if x == 'c' else x for x in orig ]
[ (a for a in orig) if x == 'c' else x for x in orig ]
[ a for a in orig if x == 'c' else x for x in orig ]

编辑:明确表示我的意思是替换该项目的所有次出现,而不仅仅是第一次出现。 (向没有在回答中涵盖该案例的任何人道歉。)

【问题讨论】:

    标签: python list-comprehension


    【解决方案1】:
    >>> orig = [ 'a', 'b', 'c', 'd' ]
    >>> repl = [ 'x', 'y', 'z' ]
    >>> desired = list(orig)  #can skip this and just use `orig` if you don't mind modifying it (and it is a list already)
    >>> desired[2:3] = repl
    >>> desired
    ['a', 'b', 'x', 'y', 'z', 'd']
    

    当然,如果您不知道'c' 位于索引2,您可以使用orig.index('c') 来查找该信息。

    【讨论】:

    • 删除了我的答案,因为它和你的几乎一样:-)
    • 您应该使用desired = list(orig) 以使其对初学者更具可读性,并使处理任何类型的 repl 和 orig 的声明有效
    • @JBernardo -- 很公平 :) 好建议。已编辑。虽然,初学者应该知道x[:] 是复制列表的一种速记方式——(声明没有证据可遵循)这可能是复制列表的最快方式...
    • 继续调用 orig.index('c') 直到它最终抛出 ValueError?这很昂贵,而且代码看起来也很尴尬。
    • @tdelaney -- 当我发帖时,orig 中只有 1 个“c”,并且没有迹象表明 OP 想要替换多次出现。
    【解决方案2】:

    不同的方法:当我做替换时,我更喜欢从字典的角度来思考。所以我会做类似的事情

    >>> orig = [ 'a', 'b', 'c', 'd' ]
    >>> rep = {'c': ['x', 'y', 'z']}
    >>> [i for c in orig for i in rep.get(c, [c])]
    ['a', 'b', 'x', 'y', 'z', 'd']
    

    最后一行是标准的扁平化习语。

    这种方法的一个优点(缺点?)是它可以处理多次出现的'c'

    [更新:]

    或者,如果您愿意:

    >>> from itertools import chain
    >>> list(chain.from_iterable(rep.get(c, [c]) for c in orig))
    ['a', 'b', 'x', 'y', 'z', 'd']
    

    关于修改后的测试用例:

    >>> orig = [ 'a', 'b', 'c', 'd', 'c' ]
    >>> rep = {'c': ['x', 'y', 'z']}
    >>> list(chain.from_iterable(rep.get(c, [c]) for c in orig))
    ['a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z']
    

    【讨论】:

    • 优势!我应该在我的问题中明确表示我需要替换所有实例,而不仅仅是第一个。
    • @DSM -- 这是标准的扁平化习语吗?一路上我错过了那个——也许是因为我仍然很难解析它:)。 itertools.chain 为我...
    • @mgilson:嗯,这是标准的 listcomp 扁平化习语。 :^)
    • 既然你已经添加了chain,我会赞成:)。虽然,值得指出的是,这个答案对列表元素施加了哈希性(至少对于您想要替换的元素)。大多数时候,这没什么大不了的,但偶尔可能会这样。
    【解决方案3】:

    不需要任何花哨的东西:

    desired = orig[:2] + repl + orig[3:]
    

    要查找2,您可以搜索orig.index('c')

    x = orig.index('c')
    desired = orig[:x] + repl + orig[x+1:]
    

    如果 repl 不是列表,则使用list(repl)

    【讨论】:

    • 足够公平 (+1) ... 虽然这仅在 repl 的类型与 orig 的类型相同时才有效。如果repl 是生成器,我的回答甚至会起作用:-)
    【解决方案4】:

    如果你向后枚举,你可以在你去的时候扩展列表,因为你移动的项目已经通过了枚举。

    >>> orig = [ 'a', 'b', 'c', 'd', 'c' ]
    >>> repl = [ 'x', 'y', 'z' ]
    >>> desired = [ 'a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z' ]
    >>> for i in xrange(len(orig)-1, -1, -1):
    ...     if orig[i] == 'c':
    ...             orig[i:i+1] = repl
    ... 
    >>> orig
    ['a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z']
    

    【讨论】:

      【解决方案5】:

      另一种方式:

      >>> import operator
      >>> orig = [ 'a', 'b', 'c', 'd', 'c' ]
      >>> repl = [ 'x', 'y', 'z' ]
      >>> output = [repl if x == 'c' else [x] for x in orig]
      >>> reduce(operator.add, output)
      ['a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z']
      >>> 
      

      【讨论】:

        猜你喜欢
        • 2013-08-26
        • 2022-07-18
        • 1970-01-01
        • 2016-02-18
        • 2019-12-24
        • 1970-01-01
        • 1970-01-01
        • 2022-10-20
        • 2022-11-12
        相关资源
        最近更新 更多