developer tip

두 범위 함수 결과 연결

optionbox 2021. 1. 10. 17:07
반응형

두 범위 함수 결과 연결


범위 함수가 연결을 허용합니까? 내가 만들고 싶고 range(30)그것을 range(2000, 5002). 따라서 연결된 범위는0, 1, 2, ... 29, 2000, 2001, ... 5001

이와 같은 코드는 내 최신 파이썬에서 작동하지 않습니다 (버전 : 3.3.0).

range(30) + range(2000, 5002)

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에서는 반복기가 메모리 효율적이지만 항상 바람직하지는 않습니다.

목록은와 연결할 수 있지만 +반복자는 연결할 수 없습니다.


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

가능한 가장 간단한 솔루션 (효율성 포함)을 좋아합니다. 해결책이 그런 것인지 항상 분명하지는 않습니다. 어쨌든 range()파이썬 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와 표준 라이브러리 사용에 대한 그의 주장으로 이동합니다. 에서 파이썬의 선 ...

모호함에도 불구하고 추측하려는 유혹을 거부하십시오.

#!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 배 더 빠릅니다.


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]

range() Python 2.x에서는 목록을 반환합니다.

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

xrange() Python 2.x에서는 반복자를 반환합니다.

>>> xrange(10)
xrange(10)

And in Python 3 range() also returns an iterator:

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

So it is clear that you can not concatenate iterators other by using chain() as the other guy pointed out.


From python3.5+, you can use iterable unpacking in lists (see PEP 448: Additional Unpacking Generalizations).

If you need a list,

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

This preserves order and does not remove duplicates. Or, you might want a tuple,

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

... or a set,

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

It also happens to be faster than calling 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)

The benefit of chain, however, is that you can pass an arbitrary list of ranges.

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

OTOH, unpacking generalisations haven't been "generalised" to arbitrary sequences, so you will still need to unpack the individual ranges yourself.


I came to this question because I was trying to concatenate an unknown number of ranges, that might overlap, and didn't want repeated values in the final iterator. My solution was to use set and the union operator like so:

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

ReferenceURL : https://stackoverflow.com/questions/14099872/concatenating-two-range-function-results

반응형