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: MEDIUM_HARD

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)))


def printable(arr):
	return ','.join((str(x) for x in arr)) if len(arr) < 3 else f'{arr[0]}-{arr[-1]}'

def solution(args):
	(chunk, ret) = ([], [])
	for i in args:
		if not len(chunk) or i == chunk[-1] + 1:
			chunk.append(i)
		else:
			ret.append(printable(chunk))
			chunk = [i]
	ret.append(printable(chunk))
	return ','.join(ret)


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)
			res += r
			idx += 1
	return res

def isRange(rng: List[int], idx: int) -> bool:
	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]:
	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
	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