converting a list of integers into range in python

后端 未结 11 1371
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-28 07:35

Is there something existing in python that can convert an increasing list of integers into a range list

E.g. given the set {0, 1, 2, 3, 4, 7, 8, 9, 11} I want to get

相关标签:
11条回答
  • 2020-11-28 08:05

    This is an improvement over the very elegant answer. This one covers non-unique and non-sorted input and is python3 compatible too:

    import itertools
    
    def to_ranges(iterable):
        iterable = sorted(set(iterable))
        for key, group in itertools.groupby(enumerate(iterable),
                                            lambda t: t[1] - t[0]):
            group = list(group)
            yield group[0][1], group[-1][1]
    

    Example:

    >>> x
    [44, 45, 2, 56, 23, 11, 3, 4, 7, 9, 1, 2, 2, 11, 12, 13, 45]
    
    >>> print( list(to_ranges(x))) 
    [(1, 4), (7, 7), (9, 9), (11, 13), (23, 23), (44, 45), (56, 56)]
    
    0 讨论(0)
  • 2020-11-28 08:08

    In the case there is no such feature in python, here is an implementation

    p = []
    last = -2                                                            
    start = -1
    
    for item in list:
        if item != last+1:                        
            if start != -1:
                p.append([start, last])
            start = item
        last = item
    
    p.append([start, last])
    
    0 讨论(0)
  • 2020-11-28 08:09

    Related questions for the case when step sizes other than 1 are of interest and a near duplicate of this question here. A solution for either case that performs well is given here.

    0 讨论(0)
  • 2020-11-28 08:12

    I think the other answers are hard to understand, and probably inefficient. Hope this is easier and faster.

    def ranges(ints):
        ints = sorted(set(ints))
        range_start = previous_number = ints[0]
        for number in ints[1:]:
            if number == previous_number + 1:
                previous_number = number
            else:
                yield range_start, previous_number
                range_start = previous_number = number
        yield range_start, previous_number
    
    0 讨论(0)
  • 2020-11-28 08:13

    Using itertools.groupby() produces a concise but tricky implementation:

    import itertools
    
    def ranges(i):
        for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
            b = list(b)
            yield b[0][1], b[-1][1]
    
    print(list(ranges([0, 1, 2, 3, 4, 7, 8, 9, 11])))
    

    Output:

    [(0, 4), (7, 9), (11, 11)]
    
    0 讨论(0)
提交回复
热议问题