Formatting Sequential Numbers

I am trying to format a list of integers with Python, and I have several difficulties in achieving what I would like.

The input is a sorted list of integers:

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

I would like the output to be a line that looks like this:

 outputString = "1-3, 6, 8-9" 

So far I have managed to achieve this:

 outputString = "1-2-3, 6, 8-9" 

It is difficult for me to report that my code ignores Int if it has already been sequential.

Here is my code:

 def format(l): i = 0 outputString = str(l[i]) for x in range(len(l)-1): if l[i + 1] == l[i]+1 : outputString += '-' + str(l[i+1]) else : outputString += ', ' + str(l[i+1]) i = i + 1 return outputString 

Thanks for your help and understanding :)

+5
source share
5 answers

You can use groupby and count from the itertools module as follows:

Edit:

Thanks to @asongtoruin comment. To remove duplicates from 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 to get nice 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 suggest that using itertools modules can confuse many Python new developers. This is why I decided to rewrite the same solution without importing the package and not 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'] 
+6
source
 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.

+2
source

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

Here's the O(n) string 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 repl.it

+2
source

Not the most readable solution, but it does its job. First, you can determine the jumps in your data (jump = difference between two elements is greater than 1). Then you just go through the source list and collect the relevant elements and append them to the line.

 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' 
+1
source

This seems a little shorter than the current answers, but still pretty readable.

There might be a nicer way to do this without creating an object with an explicit loop, but I could not think about it.

 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]) 
+1
source

Source: https://habr.com/ru/post/1265568/


All Articles