81

Does range function allows concatenation ? Like i want to make a range(30) & concatenate it with range(2000, 5002). So my concatenated range will be 0, 1, 2, ... 29, 2000, 2001, ... 5001

Code like this does not work on my latest python (ver: 3.3.0)

range(30) + range(2000, 5002)
4

8 回答 8

86

您可以itertools.chain为此使用:

from itertools import chain
concatenated = chain(range(30), range(2000, 5002))
for i in concatenated:
     ...

它适用于任意迭代。请注意,range()您应该了解 Python 2 和 3 之间的行为差​​异:在 Python 2 中range返回一个列表,而在 Python3 中返回一个迭代器,这是节省内存的,但并不总是可取的。

列表可以与 连接+,迭代器不能。

于 2012-12-31T09:36:22.427 回答
49

我喜欢可能的最简单的解决方案(包括效率)。解决方案是否如此并不总是很清楚。无论如何,range()Python 3 中的 是一个生成器。您可以将其包装到任何进行迭代的构造中。list()能够从任何可迭代对象构造列表值。列表的+运算符进行连接。我在示例中使用了较小的值:

>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(10, 20))
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> list(range(5)) + list(range(10,20))
[0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

range(5) + range(10, 20)正是 Python 2.5 中所做的——因为range()返回了一个列表。

在 Python 3 中,它仅在您真的想要构造列表时才有用。否则,我推荐使用itertools.chain的Lev Levitsky 的解决方案。该文档还显示了非常简单的实现:

def chain(*iterables):
    # chain('ABC', 'DEF') --> A B C D E F
    for it in iterables:
        for element in it:
            yield element

Inbar Rose的解决方案很好,功能也相当。无论如何,我的 +1 是给 Lev Levitsky 和他关于使用标准库的论点。来自Python 之禅...

面对模棱两可,拒绝猜测的诱惑。

#!python3
import timeit
number = 10000

t = timeit.timeit('''\
for i in itertools.chain(range(30), range(2000, 5002)):
    pass
''',
'import itertools', number=number)
print('itertools:', t/number * 1000000, 'microsec/one execution')

t = timeit.timeit('''\
for x in (i for j in (range(30), range(2000, 5002)) for i in j):
    pass
''', number=number)
print('generator expression:', t/number * 1000000, 'microsec/one execution')

在我看来,itertools.chain它更具可读性。但真正重要的是...

itertools: 264.4522138986938 microsec/one execution
generator expression: 785.3081048010291 microsec/one execution

...速度快了大约 3 倍。

于 2012-12-31T12:40:38.527 回答
37

可以使用list-comprehension来完成。

>>> [i for j in (range(10), range(15, 20)) for i in j]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 18, 19]

适合您的要求,但答案很长,所以我不会在这里发布。

注意:可以制作成生成器以提高性能:

for x in (i for j in (range(30), range(2000, 5002)) for i in j):
    # code

甚至是生成器变量。

gen = (i for j in (range(30), range(2000, 5002)) for i in j)
for x in gen:
    # code
于 2012-12-31T09:52:18.210 回答
31

蟒蛇> = 3.5

您可以在列表中使用可迭代解包(参见 PEP 448:附加解包概括)。

如果你需要一份清单,

[*range(2, 5), *range(3, 7)]
# [2, 3, 4, 3, 4, 5, 6]

这会保留顺序并且不会删除重复项。或者,你可能想要一个元组,

(*range(2, 5), *range(3, 7))
# (2, 3, 4, 3, 4, 5, 6)

...或一组,

# note that this drops duplicates
{*range(2, 5), *range(3, 7)}
# {2, 3, 4, 5, 6}

它也恰好比 call 更快itertools.chain

from itertools import chain

%timeit list(chain(range(10000), range(5000, 20000)))
%timeit [*range(10000), *range(5000, 20000)]

738 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
665 µs ± 13.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

但是,的好处chain是您可以传递任意范围的列表。

ranges = [range(2, 5), range(3, 7), ...]
flat = list(chain.from_iterable(ranges))

OTOH,解包概括尚未“概括”到任意序列,因此您仍然需要自己解包各个范围。

于 2019-04-13T00:55:25.190 回答
9

借助 extend 方法,我们可以连接两个列表。

>>> a = list(range(1,10))
>>> a.extend(range(100,105))
>>> a  
[1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 101, 102, 103, 104]
于 2012-12-31T12:55:52.553 回答
4

range()在 Python 2.x 中返回一个列表:

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

xrange()在 Python 2.x 中返回一个迭代器:

>>> xrange(10)
xrange(10)

在 Python 3 中range()还返回一个迭代器:

>>> r = range(10)
>>> iterator = r.__iter__()
>>> iterator.__next__()
0
>>> iterator.__next__()
1
>>> iterator.__next__()
2

因此很明显,您不能chain()像其他人指出的那样使用其他迭代器来连接其他迭代器。

于 2012-12-31T09:43:10.713 回答
1

您可以使用范围函数周围的列表函数来制作一个像这样的列表

list(range(3,7))+list(range(2,9))
于 2020-01-09T13:44:27.040 回答
0

我来这个问题是因为我试图连接未知数量的范围,这些范围可能重叠,并且不希望最终迭代器中出现重复值。我的解决方案是这样使用setunion操作员:

range1 = range(1,4)
range2 = range(2,6)
concatenated = set.union(set(range1), set(range2)
for i in concatenated:
    print(i)
于 2016-10-28T21:58:18.790 回答