Concatenating two range function results

前端 未结 8 1249
臣服心动
臣服心动 2020-11-27 17:04

Does range function allows concatenation ? Like i want to make a range(30) & concatenate it with range(2000, 5002). So my concatenated range w

相关标签:
8条回答
  • 2020-11-27 17:21

    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
    
    0 讨论(0)
  • 2020-11-27 17:22

    You can use list function around range function to make a list LIKE THIS

    list(range(3,7))+list(range(2,9))
    
    0 讨论(0)
  • 2020-11-27 17:26

    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.

    0 讨论(0)
  • 2020-11-27 17:28

    range() in Python 2.x returns a list:

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

    xrange() in Python 2.x returns an iterator:

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

    0 讨论(0)
  • 2020-11-27 17:29

    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)
    
    0 讨论(0)
  • 2020-11-27 17:30

    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.

    0 讨论(0)
提交回复
热议问题