Convert a list of integers to a list of consecutive positive integers

Question:

I came up with this code to convert a list of already ordered integers into a list of consecutive positive integers.

def consecutive_positive_inc(l):
    """
    [0, 1, 1, 3, 4, 4, 5] -> [0, 1, 1, 2, 3, 3, 4]
    """
    from collections import defaultdict

    d = defaultdict(int)
    for i in l:
        d[i] += 1

    for i, count in enumerate(d.values()):
        for _ in range(count):
            yield i


if __name__ == '__main__':
    l = [-3, -2, -1, 0, 1, 1, 3, 4, 4, 5]
    result = list(consecutive_positive_inc(l))
    assert result == [0, 1, 2, 3, 4, 4, 5, 6, 6, 7]

Is it the best way to do it or something much simpler could be used?

Asked By: DevLounge

||

Answers:

I think you’ve made it more complicated than it needs to be. Just keep a counter and bump when the number changes.

def consecutive_positive_inc(l):
    """
    [0, 1, 1, 3, 4, 4, 5] -> [0, 1, 1, 2, 3, 3, 4]
    """
    last = l[0]
    idx = 0
    for i in l:
        if i != last:
            idx += 1
            last = i
        yield idx


if __name__ == '__main__':
    l = [-3, -2, -1, 0, 1, 1, 3, 4, 4, 5]
    result = list(consecutive_positive_inc(l))
    assert result == [0, 1, 2, 3, 4, 4, 5, 6, 6, 7]
Answered By: Tim Roberts

itertools.groupby:

from itertools import groupby

def consecutive_inc(iterable, start=0):
    """
    >>> list(consecutive_inc([0, 1, 1, 3, 4, 4, 5]))
    [0, 1, 1, 2, 3, 3, 4]
    """
    return (i for i, (_, g) in enumerate(groupby(iterable), start) for _ in g)

This uses O(1) space and works on arbitrary iterables.

Answered By: Ry-

You can use a dict like a mathematical set to keep track of how many unique numbers you have seen before:

def consecutive_positive_inc(l):
  m = {}
  r = []
  for i in l:
    m[i] = None
    r.append(len(m) - 1)
  return r
Answered By: David Grayson

You can do this in one line with a collections.Counter:

>>> from collections import Counter
>>> def consecutive_positive_inc(arr):
...     return [i for i, count in enumerate(Counter(arr).values()) for _ in range(count)]
...
>>> consecutive_positive_inc([0, 1, 1, 3, 4, 4, 5])
[0, 1, 1, 2, 3, 3, 4]
Answered By: Samwise

from collections import Counter
def consecutive_positive_inc(arr):
… return [i for i, count in enumerate(Counter(arr).values()) for _ in range(count)]

consecutive_positive_inc([0, 1, 1, 3, 4, 4, 5])
[0, 1, 1, 2, 3, 3, 4]

Answered By: Naveen
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.