web-dev-qa-db-ja.com

2つの範囲関数の結果を連結する

範囲関数は連結を許可しますか?私はrange(30)を作り、range(2000, 5002)と連結したいのです。したがって、連結範囲は0, 1, 2, ... 29, 2000, 2001, ... 5001

このようなコードは、最新のpython(ver:3.3.0)では機能しません

range(30) + range(2000, 5002)
53
MAG

これには _itertools.chain_ を使用できます。

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

任意のイテラブルに対して機能します。 range() Python 2と3の間で知っておくべき振る舞いに違いがあることに注意してください:in Python 2 range はリストを返し、Python3ではイテレータを返します。これはメモリ効率は良くなりますが、常に望ましいとは限りません。

リストは_+_と連結できますが、イテレーターは連結できません。

58
Lev Levitsky

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
34
Inbar Rose

私は可能な限り簡単なソリューション(効率を含む)が好きです。解決策がそのようなものであるかどうかは必ずしも明確ではありません。とにかく、Python 3のrange()はジェネレーターです。繰り返しを行う任意の構造にラップできます。 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では、リストを本当に構築したい場合にのみ役立ちます。それ以外の場合は、 Lev Levitskyの ソリューションと itertools.chain をお勧めします。ドキュメントには、非常に簡単な実装も示されています。

_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と、標準ライブラリの使用に関する彼の議論に行きます。 FromThe Zen of 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倍高速です。

32
pepr

Extendメソッドの助けを借りて、2つのリストを連結できます。

>>> 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]
6
Darknight

Python3.5 +から、リストで反復可能なアンパックを使用できます(PEP 448: Additional Unpacking Generalizations を参照)。

リストが必要な場合、

[*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}

また、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、一般化のアンパックは任意のシーケンスに「一般化」されていないため、個々の範囲を自分でアンパックする必要があります。

4
cs95

range() in Python 2.xはリストを返します:

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

xrange() in 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()を使用して他のイテレータを連結できないことは明らかです。

4
Andreas Jung

私はこれが少し古いスレッドであることを知っていますが、私にとっては、次のように動作します。

>>> for i in range(30) + range(2000, 5002):
...    print i

これも

>>> for i in range(30) , range(2000, 5002):
...  print i

もちろん、印刷出力は2番目と1番目では異なります。

編集:OP python 3.と述べているOPからのフォローアップコメントを逃しました。これは私のpython 2環境にあります。

0
R J

重複する可能性のある未知の数の範囲を連結しようとしていたので、この質問に来ました。最終イテレーターで値を繰り返したくないのです。私の解決策は、setunion 演算子を次のように使用することでした。

range1 = range(1,4)
range2 = range(2,6)
concatenated = set.union(set(range1), set(range2)
for i in concatenated:
    print(i)
0
raphael