【问题标题】:What is the preferred way to concatenate sequences in Python 3?在 Python 3 中连接序列的首选方法是什么?
【发布时间】:2013-01-15 16:29:39
【问题描述】:

在 Python 3 中连接序列的首选方法是什么?

现在,我正在做:

import functools
import operator

def concatenate(sequences):
    return functools.reduce(operator.add, sequences)

print(concatenate([['spam', 'eggs'], ['ham']]))
# ['spam', 'eggs', 'ham']

需要导入两个单独的模块来执行此操作似乎很笨重。

另一种可能是:

def concatenate(sequences):
    concatenated_sequence = []
    for sequence in sequences:
        concatenated_sequence += sequence
    return concatenated_sequence

但是,这是不正确的,因为您不知道序列是列表。

你可以这样做:

import copy

def concatenate(sequences):
    head, *tail = sequences
    concatenated_sequence = copy.copy(head)
    for sequence in sequences:
        concatenated_sequence += sequence
    return concatenated_sequence

但这似乎很容易出错——直接调用复制? (我知道head.copy() 适用于列表和元组,但copy 不是序列ABC 的一部分,所以你不能依赖它......如果你得到字符串怎么办?)。您必须复制以防止突变,以防您收到MutableSequence。此外,此解决方案会强制您首先解压缩整个序列集。再试一次:

import copy 

def concatenate(sequences):
    iterable = iter(sequences)
    head = next(iterable)
    concatenated_sequence = copy.copy(head)
    for sequence in iterable:
        concatenated_sequence += sequence
    return concatenated_sequence

但是来吧……这是蟒蛇!那么......最好的方法是什么?

【问题讨论】:

  • 你见过itertools.chain()吗?不过,我不确定它是否能处理您所有的预期用例。
  • 不要害怕标准库导入。其他一些模块(甚至来自标准库)很可能会获取functools 和/或operator

标签: python-3.x python-3.3


【解决方案1】:

我会改用itertools.chain.from_iterable()

import itertools

def chained(sequences):
    return itertools.chain.from_iterable(sequences):

或者,既然你用 标记了它,你可以使用新的yield from 语法(看,没有导入!):

def chained(sequences):
    for seq in sequences:
        yield from seq

它们都返回迭代器(如果您必须具体化完整列表,请在它们上使用list())。大多数情况下,您不需要从串联的序列构造一个全新的序列,实际上,您只需要循环它们来处理和/或搜索某些东西。

请注意,对于字符串,您应该使用 str.join() 而不是我的回答或您的问题中描述的任何技术:

concatenated = ''.join(sequence_of_strings)

结合起来,为了处理快速和正确的序列,我会使用:

def chained(sequences):
    for seq in sequences:
        yield from seq

def concatenate(sequences):
    sequences = iter(sequences)
    first = next(sequences)
    if hasattr(first, 'join'):
        return first + ''.join(sequences)
    return first + type(first)(chained(sequences))

这适用于元组、列表和字符串:

>>> concatenate(['abcd', 'efgh', 'ijkl'])
'abcdefghijkl'
>>> concatenate([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> concatenate([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
(1, 2, 3, 4, 5, 6, 7, 8, 9)

并为字符串序列使用更快的''.join()

【讨论】:

  • 哇,语法不错! yield from 是 3.3 中的新功能吗?
【解决方案2】:

有什么问题:

from itertools import chain
def chain_sequences(*sequences):
  return chain(*sequences)

【讨论】:

  • 我不认为这是一个问题,但实际上是试图回答。更多解释会更清楚。
  • 它在答案部分,所以看起来很清楚这是一个建议的答案。
【解决方案3】:

使用itertools.chain.from_iterable

import itertools

def concatenate(sequences):
    return list(itertools.chain.from_iterable(sequences))

仅当您需要一个实际的新列表时才需要调用list,因此如果您只对这个新序列进行一次迭代,请跳过它。

【讨论】:

  • concatenate(['a', 'b']) 将返回 ['a', 'b'] 而不是 'ab',因此这对我的用例不正确。您如何确定序列类型?
  • @ToBeReplaced:字符串连接最好用str.join()处理。
  • chain(*sequences) 工作时为什么“from_iterable”片段?
猜你喜欢
  • 1970-01-01
  • 2020-12-02
  • 2010-10-10
  • 2012-08-23
  • 1970-01-01
  • 1970-01-01
  • 2018-08-10
  • 2014-04-06
  • 1970-01-01
相关资源
最近更新 更多