Skip to content Skip to sidebar Skip to footer

Formatting Consecutive Numbers

I'm trying to format a list of integers with Python and I'm having a few difficulties achieving what I'd like. Input is a sorted list of Integers: list = [1, 2, 3, 6, 8, 9] I wou

Solution 1:

You can use groupby and count from itertools module like this way:

Edit:

Thanks to @asongtoruin comment. For removing duplicates from the input you can use: sorted(set(a)).

from itertools import groupby, count

a = [1, 2, 3, 6, 8, 9]
clustered = [list(v) for _,v in groupby(sorted(a), lambda n, c = count(): n-next(c))]

for k in clustered:
    iflen(k) > 1:
        print("{0}-{1}".format(k[0], k[-1]))
    else:
        print("{0}".format(k[0]))

Output:

1-3
6
8-9

Or maybe you can do something like this in order to have a pretty output:

from itertools import groupby, count

a = [1, 2, 3, 6, 8, 9]
clustered = [list(v) for _,v in groupby(sorted(a), lambda n, c = count(): n-next(c))]
out = ", ".join(["{0}-{1}".format(k[0], k[-1]) iflen(k) > 1else"{0}".format(k[0]) for k in clustered ])

print(out)

Output:

1-3, 6, 8-9

Update:

I'm guessing, using itertools modules may confuse many Python's new developers. This is why i decided to rewrite the same solution without importing any package and trying to show what groupby and count are doing behind the scenes:

defcount(n=0, step=1):
    """Return an infinite generator of numbers"""whileTrue:
        n += step
        yield n


defconcat(lst):
    """Group lst elements based on the result of elm - next(_count)"""
    _count, out = count(), {}
    for elm insorted(lst):
        c = elm - next(_count)
        if c in out:
            out[c].append(elm)
        else:
            out[c] = [elm]
    return out


defpretty_format(dct):
    for _, value in dct.items():
        iflen(value) > 1:
            yield'{}-{}'.format(value[0], value[-1])
        else:
            yield'{}'.format(value[0])


lst = [1, 2, 3, 6, 8, 9]
dct = concat(lst)
formatted = list(pretty_format(dct))
print(formatted)

Output:

['1-3', '6', '8-9']

Solution 2:

list=[1, 2, 3, 4, 6, 10, 11, 12, 13]
y=str(list[0])

for i inrange(0, len(list)-1):
    iflist[i+1] == list[i]+1 :
        y+= '-' + str(list[i + 1])
    else:
        y+= ',' + str(list[i + 1])
print y


z= y.split(',')
outputString= ''for i in z:
    p=i.split('-')
    if p[0] == p[len(p)-1]:
        outputString = outputString + str(p[0]) + str(',')
    else:
        outputString = outputString + str(p[0]) + str('-') + str(p[len(p) - 1]) + str(',')

outputString = outputString[:len(outputString) - 1]
print'final ans: ',outputString

add these lines after your code.

Solution 3:

Since the other guy who posted this solution deleted his answer...

Here's a O(n) string building solution:

def stringify(lst):
    result= str(lst[0])
    end=Nonefor index, num in enumerate(lst[1:]):
        if num -1== lst[index]:  # the slice shifts the index by1for us
            end= str(num)
        else:
            if end:
                result+='-'+endend=Noneresult+=', '+ str(num)
    # Catch the last term
    if end:
        result+='-'+ str(num)
    returnresult

See the repl.it

Solution 4:

Not the most readable solution but gets the job done. One can first determine jumps in your data (jump = difference between two elements is greater than 1). Then you just loop through you original list and collect the respective elements and join them to a string.

import numpy as np

l = np.array([1, 2, 3, 6, 8, 9])

# find indexes of jumps in your data
l_diff = np.where(np.diff(l) > 1)[0] + 1# add one index which makes slicing easier later onif l_diff[0] != 0:
    l_diff = np.insert(l_diff, 0, 0)

# add all the data which are groups of consecutive values
res = []    
for ix, i inenumerate(l_diff):
    try:
        sl = l[i:l_diff[ix + 1]]
        iflen(sl) > 1:
            res.append([sl[0], sl[-1]])
        else:
            res.append(sl)
    # means we reached end of l_diffexcept IndexError:
        sl = l[i:]
        iflen(sl) > 1:
            res.append([sl[0], sl[-1]])
        else:
            res.append(sl)


# join the data accordingly, we first have to convert integers to strings
res = ', '.join(['-'.join(map(str, ai)) for ai in res])

Then res is

'1-3, 6, 8-9'

Solution 5:

This seems a bit shorter than the current answers but is still pretty readable.

There might be a nicer way to do it without building an object up with an explicit loop, but I couldn't think of one.

L = [1, 2, 3, 6, 8, 9]

runs = [[str(L[0])]]

forfirst, secondin zip(L, L[1:]):
    if second==first+1:
        runs[-1].append(str(second))
    else:
        runs.append([str(second)])

result= ", ".join(["-".join(run) for run in runs])

Post a Comment for "Formatting Consecutive Numbers"