B
B
be1ay2015-04-02 13:30:58
Python
be1ay, 2015-04-02 13:30:58

How to implement an algorithm for constructing a string from a list of ordered integers?

I'm trying to write a function that takes an ordered list of integers, and should return a string in which if more than two numbers go in order, you need to replace it with an abbreviated notation. For example, if the input is a list of 1,2,3,5, the output should be 1-3.5. But if the input is 1,2,5, then it should remain 1,2,5.
Here is my function, but it only works correctly for a particular case (when there are more than 2 consecutive numbers). How to correct or it is possible to implement this algorithm differently?

def myfunc(intList,k):
  if len(intList)==1:
    return str(intList[0])
  else:
    if intList[1]-intList[0]==1:
      if k==0:
        k=+1
        return str(intList[0])+'-'+str(myfunc(intList[1:],k))
      if k==1:
        return str(myfunc(intList[1:],k))
    else:
      k=0
      return str(intList[0])+','+str(myfunc(intList[1:],k))

print(myfunc([1,2,3,4,7,9,11,13,14,15,16,17,19],0))
print(myfunc([5,6,15,16],0))

Conclusion:

1-4,7,9,11,13-17,19
5-6,15-16

In the first case, it displays as it should, but this is a special case.
In the second case, it is clear that the function does not work correctly.

Answer the question

In order to leave comments, you need to log in

4 answer(s)
A
Andrey K, 2015-04-02
@be1ay

def fl(l):
    if len(l) > 2:
        return '%s-%s' % (l[0], l[-1])
    elif len(l) == 2:
        return '%s, %s' % (l[0], l[-1])
    else:
        return '%s' % l[0]

def cc(l):
    r = []
    b = []
    for i in l:
        if len(b) > 0:
            if i - b[-1] == 1:
                b.append(i)
            else:
                r.append(fl(b))
                b = [i]
        else:
            b.append(i)
    else:
        r.append(fl(b))

    return ', '.join(r)

V
Valentine, 2015-04-02
@vvpoloskin

If you want it easier, keep it. The logic is this: you need to insert the "-" symbol into the list where the difference between two adjacent numbers > 1. And then this list is converted to a string.

def getstr(l):
    nl = [l[0],]
    for i in range(1, len(l)):
        if l[i] - nl[-1] > 1 and nl[-2] != '-':
            nl.append('-')
        nl.append(l[i])
    return nl

l = [1,2,3,4,7,9,11,13,14,15,16,17,19]
nl = getstr(l)
print(','.join(nl).replace(',-,', '-'))

I can even simpler, but then you will not understand the code at all

L
localghost, 2015-04-03
@localghost

It seems to me that Andrey has a great code, but here's another option. Similar to yours, but without the recursion.
You just need to keep both the beginning and the end of the range. Well, with the last element, a slightly special task - almost the same as simply closing the range, but with a slight correction. Otherwise, it is either duplicated or not added at all.

def closeInt(rS, rE):
    if rE - rS == 1:
        return ", " + str(rE)
    if rE - rS > 1:
        return "-" + str(rE)
    return ""

def shortify(intlist):
    result = str(intlist[0])
    
    rangeStart = intlist[0]
    rangeEnd = intlist[0]
    for i in range(1, len(intlist)):
        if intlist[i] == intlist[i-1] + 1:
            rangeEnd += 1
        else:
            result += closeInt(rangeStart, rangeEnd)
            result += ", " + str(intlist[i])
            rangeStart = intlist[i]
            rangeEnd = intlist[i]
    
    result += closeInt(rangeStart, intlist[-1])
    return result

print(shortify([1]))
print(shortify([2,3]))
print(shortify([2,4]))
print(shortify([4,5,6]))
print(shortify([1,2,3,4,7,9,11,13,14,15,16,17,19]))
print(shortify([1,2,4,7,8,11,12,13,14,15,16,18,19]))
print(shortify([1,2,3,4,7,9,11,13,14,15,17,18,19]))

S
some1else, 2015-04-16
@some1else

Here is the working code. The whole simple essence of the method is to replace with 0 all numbers that have left-right neighbors -1 and + 1, respectively, then run through the obtained values, replacing all consecutive 0s with '-'. Glue the result through ',', and finally replace ',-,' with '-'

from itertools import groupby

def drop_inner(nums):
    for a, b, c in zip([0, 0] + nums, [0] + nums + [0], nums + [0, 0]):
        if b:
            yield 0 if a and c and (a + 1 == b == c - 1) else b

def shorten(nums):
    return ','.join(
        str(x) if x else '-' for x, _ in groupby(drop_inner(nums))
    ).replace(',-,', '-')

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question