A format for expressing an ordered list of integers is to use a comma separated list of either

* individual integers
* or a range of integers denoted by the starting integer separated from the end integer in the range by a dash, '-'. The range includes all integers in the interval including both endpoints.  It is not considered a range unless it spans at least 3 numbers. For example "12,13,15-17"

Complete the solution  so that it takes a list of integers in increasing order and returns a correctly formatted string in the range format. 

**Example:**

```python
solution([-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20])
# returns "-6,-3-1,3-5,7-11,14,15,17-20"
```

```C#
RangeExtraction.Extract(new[] {-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20});
# returns "-6,-3-1,3-5,7-11,14,15,17-20"
```

*Courtesy of rosettacode.org*

Difficulty: interview

Starter code:

def solution(args):
	

Solutions:
def solution(args):
    out = []
    beg = end = args[0]
    
    for n in args[1:] + [""]:        
        if n != end + 1:
            if end == beg:
                out.append( str(beg) )
            elif end == beg + 1:
                out.extend( [str(beg), str(end)] )
            else:
                out.append( str(beg) + "-" + str(end) )
            beg = n
        end = n
    
    return ",".join(out)

def solution(arr):
    ranges = []
    a = b = arr[0]
    for n in arr[1:] + [None]:
        if n != b+1:
            ranges.append(str(a) if a == b else "{}{}{}".format(a, "," if a+1 == b else "-", b))
            a = n
        b = n
    return ",".join(ranges)


def solution(args):
    result = ""
    i = 0
    while i<len(args):
        val = args[i]
        while i+1<len(args) and args[i]+1==args[i+1]:
            i+=1
        if val == args[i]:
            result += ",%s"%val
        elif val+1 == args[i]:
            result += ",%s,%s"%(val, args[i])
        else:
            result += ",%s-%s"%(val, args[i])
        i+=1
    return result.lstrip(",")

from itertools import groupby
def solution(args):
    grps = ([v[1] for v in g] for _,g in groupby(enumerate(args), lambda p: p[1]-p[0]))
    return ','.join('{}{}{}'.format(g[0],'-'if len(g)>2 else',',g[-1])
        if len(g)>1 else str(g[0]) for g in grps)

from itertools import groupby

class Conseq:
    def __init__(self):
        self.value = None
        self.key = 0
    def __call__(self, value):
        if self.value is None or (value != self.value + 1):
            self.key += 1
        self.value = value
        return self.key

def serial(it):
    first = last = next(it)
    for last in it:
        pass
    if first == last:
        yield str(first)
    elif first + 1 == last:
        yield str(first)
        yield str(last)
    else:
        yield '{}-{}'.format(first, last)

def solution(args):
    return ','.join(r for _, grp in groupby(args, key=Conseq()) for r in serial(grp))

""" noob solution, explained for noobs :) """

def printable(arr):
    return (','.join(str(x) for x in arr) if len(arr) < 3  # one or two consecutive integers : comma separated
            else f'{arr[0]}-{arr[-1]}')                    # more : dash separated first and last integer

def solution(args):
    chunk, ret = [], []                                    # instantiate variables

    for i in args:                                         # for each integer
        if not len(chunk) or i == chunk[-1] + 1:           #     if first or consecutive
            chunk.append(i)                                #         add to current chunk
        else:                                              #     else, it's a gap
            ret.append(printable(chunk))                   #         save current chunk
            chunk = [i]                                    #         and restart a new one

    ret.append(printable(chunk))                           # do not forget last chunk !

    return ','.join(ret)                                   # return comma separated chunks

from itertools import groupby
def solution(args):
    d=''
    fun = lambda x: x[1] - x[0]
    for k, g in groupby(enumerate(args), fun):
        c=[b for a,b in g]
        if len(c)==1:
            d=d+'%d,'%c[0]
        elif len(c)==2:
            d=d+'%d,%d,'%(c[0],c[-1])
        else:
            d=d+'%d-%d,'%(c[0],c[-1])
    return (d[:-1])

def solution(args):
    
    temp, segments = list(), list()
    
    while args:
        temp.append(args.pop(0))
        
        if len(args) != 0 and temp[-1] == args[0] - 1:
            continue
        
        if len(temp) <= 2:
            segments += temp
        else:
            segments.append(f'{temp[0]}-{temp[-1]}')
            
        temp = []
    
    return ','.join(str(s) for s in segments)

from typing import List, Tuple


def solution(args: List[int]) -> str:
    res: str = ""
    length: int = len(args)
    idx: int = 0

    while idx < length:
        if isRange(args, idx):
            r, inc = showRange(args, idx)
            res += r
            idx += inc
        else:
            r = showInt(args, idx)  # handles separator
            res += r
            idx += 1
    return res


def isRange(rng: List[int], idx: int) -> bool:
    # a range spans at least 3 integers
    if len(rng)-3 < idx:
        return False

    n: int = rng[idx]
    nn: int = rng[idx+1]
    nnn: int = rng[idx+2]
    if n+1 == nn and nn+1 == nnn:
        return True

    return False


def showRange(rng: List[int], idx: int) -> Tuple[str, int]:
    # determine range
    # determine if range spans until the end (for separator!)
    curr: int = idx
    length: int = len(rng)
    while rng[curr]+1 == rng[curr+1]:
        curr += 1
        if (curr+1 == length):
            break

    res: str = str(rng[idx]) + "-" + str(rng[curr])
    dist: int = curr - idx + 1
    assert(dist >= 3)  # implied by the algorithm
    if not atEnd(rng, curr):
        res += ","

    return (res, dist)


def showInt(rng: List[int], idx: int) -> str:
    res: str = str(rng[idx])
    if atEnd(rng, idx):
        return res
    else:
        return res + ","


def atEnd(lst: List, idx: int) -> bool:
    return len(lst)-1 == idx