Подтвердить что ты не робот

Конкатенация результатов двух диапазонов

Позволяет ли функция диапазона конкатенации? Как я хочу сделать range(30) и объединить его с помощью range(2000, 5002). Таким образом, мой конкатенированный диапазон будет 0, 1, 2, ... 29, 2000, 2001, ... 5001

Код, подобный этому, не работает на моем последнем python (ver: 3.3.0)

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

Ответ 1

Вы можете использовать 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 - итератор, который эффективен с точки зрения памяти, но не всегда желателен.

Списки могут быть объединены с помощью +, итераторы не могут.

Ответ 2

Может быть сделано с помощью 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

Ответ 3

Мне нравятся самые простые решения, которые возможны (включая эффективность). Не всегда ясно, является ли решение таким. Во всяком случае, 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. Документация также показывает очень простую реализацию:

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 идет к Льву Левицкому и его аргументу об использовании стандартных библиотек. Из дзен питона...

Перед лицом двусмысленности откажитесь от соблазна гадать.

#!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.chain. Но что действительно важно...

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

... это примерно в 3 раза быстрее.

Ответ 4

С помощью метода 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]

Ответ 5

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(), как указал другой парень.

Ответ 6

Начиная с python3. 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}

Это также происходит быстрее, чем вызов 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, распаковка обобщений не была "обобщена" на произвольные последовательности, поэтому вам все равно придется распаковывать отдельные диапазоны самостоятельно.

Ответ 7

Я пришел к этому вопросу, потому что пытался объединить неизвестное количество диапазонов, которые могли бы перекрываться, и не нуждались в повторных значениях в конечном итераторе. Мое решение заключалось в том, чтобы использовать set и union:

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

Ответ 8

Я знаю, что это немного старая тема, но для меня работает следующее.

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

Так ли это

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

Конечно, вывод на печать во втором отличается от первого.

Изменение: я пропустил последующий комментарий от OP, заявив Python 3. Это в моей среде Python 2.