Concatenating two range function results

63,457

Solution 1

You can use itertools.chain for this:

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

It works for arbitrary iterables. Note that there's a difference in behavior of range() between Python 2 and 3 that you should know about: in Python 2 range returns a list, and in Python3 an iterator, which is memory-efficient, but not always desirable.

Lists can be concatenated with +, iterators cannot.

Solution 2

I like the most simple solutions that are possible (including efficiency). It is not always clear whether the solution is such. Anyway, the range() in Python 3 is a generator. You can wrap it to any construct that does iteration. The list() is capable of construction of a list value from any iterable. The + operator for lists does concatenation. I am using smaller values in the example:

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

This is what range(5) + range(10, 20) exactly did in Python 2.5 -- because range() returned a list.

In Python 3, it is only useful if you really want to construct the list. Otherwise, I recommend the Lev Levitsky's solution with itertools.chain. The documentation also shows the very straightforward implementation:

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

The solution by Inbar Rose is fine and functionally equivalent. Anyway, my +1 goes to Lev Levitsky and to his argument about using the standard libraries. From The Zen of Python...

In the face of ambiguity, refuse the temptation to guess.

#!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')

In my opinion, the itertools.chain is more readable. But what really is important...

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

... it is about 3 times faster.

Solution 3

Can be done using 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]

Works for your request, but it is a long answer so I will not post it here.

note: can be made into a generator for increased performance:

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

or even into a generator variable.

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

Solution 4

python >= 3.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.

Solution 5

With the help of the extend method, we can concatenate two lists.

>>> 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]
Share:
63,457

Related videos on Youtube

MAG
Author by

MAG

I am I .

Updated on January 10, 2020

Comments

  • MAG
    MAG over 4 years

    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)
    
    • MAG
      MAG over 11 years
      the version of my python is version 3.3.0 .. i have also updated in my question
    • Karl Knechtel
      Karl Knechtel over 11 years
      What do you want to get as a result (as in, what type of data - a plain list, a generator, something else)? What do you want to do with the result?
  • Inbar Rose
    Inbar Rose over 11 years
    your answer is helpful, but does not provide a solution.
  • Inbar Rose
    Inbar Rose over 11 years
    @mkind thanks, i hate dependencies, people always jump and answer with tons of imports and libraries, but they are not always available, and they often times do the same thing that normal code does, only wrapped in a package, its not magic. :)
  • Lev Levitsky
    Lev Levitsky over 11 years
    I don't think that not using standard libraries is a virtue on its own, but this is a nice answer.
  • mkind
    mkind over 11 years
    @inbar, you're right. two additional advantage are that you know what the code does and that you are learning something about the problem.
  • Inbar Rose
    Inbar Rose over 11 years
    @LevLevitsky /mkind : the code for chain: docs.python.org/2/library/itertools.html#itertools.chain is exactly what my list-comprehension/generator does, only you dont need to import anything, and you can see it right in front of you/modify it if you need with conditions etc...
  • pepr
    pepr over 11 years
    @mkind and Inbar Rose: Hating dependencies may be OK, but the itertools module is the standard one. Because of its more efficient implementation, the solution with itertools.chain is about 3 times faster -- see stackoverflow.com/a/14101734/1346705. The moral is: "Never say never!"
  • Inbar Rose
    Inbar Rose over 11 years
    this is great, i will admit defeat by efficiently built standard library modules. but your timing is strange, on my machine after numerous tests, i found that my solution is only about 1.8 times slower, as opposed to 3 times slower. but it is still slower.
  • pepr
    pepr over 11 years
    It is definitely hardware dependent and could be also OS dependent. I did use my rather obsolete computer with AMD Athlon 64 X2 Dual Core Processor 3800+ at 2.01 GHz, with 3 GB of memory. The OS is Windows 7 Home Premium 64 bit (both processor and memory score is only 4,9 -- windows.microsoft.com/en-US/windows7/…). I am not sure about the Python implementation. Say, you may have more processor cores.
  • Lev Levitsky
    Lev Levitsky over 11 years
    This is for Python 2, the OP uses Python 3.
  • mkind
    mkind over 11 years
    @pepr i totally agree. although, i try to use as less deps as possible.
  • user7610
    user7610 over 9 years
    Extend is not a keyword, it is a method on Python lists.
  • cs95
    cs95 about 5 years
    This will not maintain order unless python3.7, this will also not allow for partial overlaps in ranges (ie, allow for duplicates).
  • Tuchar Das
    Tuchar Das over 4 years
    What change did u made in my answer? Can u mail me?I Did not notice it.Is it the Indentation
  • Amos Folarin
    Amos Folarin over 4 years
    For me, this has to be one of the ugliest bits of Python. For such a basic task to have external lib requirement for this is ridiculous...
  • Amos Folarin
    Amos Folarin over 4 years
    Thanks -- this is much nicer, cleaner than the suggested answer.
  • mahyard
    mahyard over 4 years
    by adding 4 space characters at the beginning of a line you indicate that it contains source code and should be highlighted. you can instead select the code block and click on {} button of the editor.
  • ankostis
    ankostis about 4 years
    @cs95 Order is not maintained even in Python-3.7 -- it' the dict that keeps the order, not the set, which till sort them according to value hashes.
  • ankostis
    ankostis about 4 years
    @amos-folarin I tend to agree, that's why i was impressed to find coconut, a python-like language with all functional tools readily available as syntactic sugar.
  • wfaulk
    wfaulk about 3 years
    Beware: you cannot save a chain to use a second time. You get to iterate over it once. If you try again, you get nothing. This is in stark contrast to how a range works.
  • Ivan Shatsky
    Ivan Shatsky about 2 years
    For a python novice like me this took a couple of time to understand; the for loop inheritance looks some kind of non-obvious. Please consider to add an additional explanation like this one I'd just posted as an example.