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:
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])]]
for first, second in 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])
list=[1, 2, 3, 4, 6, 10, 11, 12, 13]
y=str(list[0])
for i in range(0, len(list)-1):
if list[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.
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 on
if 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 in enumerate(l_diff):
try:
sl = l[i:l_diff[ix + 1]]
if len(sl) > 1:
res.append([sl[0], sl[-1]])
else:
res.append(sl)
# means we reached end of l_diff
except IndexError:
sl = l[i:]
if len(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'
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 = None
for index, num in enumerate(lst[1:]):
if num - 1 == lst[index]: # the slice shifts the index by 1 for us
end = str(num)
else:
if end:
result += '-' + end
end = None
result += ', ' + str(num)
# Catch the last term
if end:
result += '-' + str(num)
return result
See the repl.it
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:
if len(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]) if len(k) > 1 else "{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:
def count(n=0, step=1):
"""Return an infinite generator of numbers"""
while True:
n += step
yield n
def concat(lst):
"""Group lst elements based on the result of elm - next(_count)"""
_count, out = count(), {}
for elm in sorted(lst):
c = elm - next(_count)
if c in out:
out[c].append(elm)
else:
out[c] = [elm]
return out
def pretty_format(dct):
for _, value in dct.items():
if len(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']