90 lines
2.2 KiB
Python
90 lines
2.2 KiB
Python
'''Range extraction'''
|
|
|
|
from functools import reduce
|
|
|
|
|
|
# rangeFormat :: [Int] -> String
|
|
def rangeFormat(xs):
|
|
'''Range-formatted display string for
|
|
a list of integers.
|
|
'''
|
|
return ','.join([
|
|
rangeString(x) for x
|
|
in splitBy(lambda a, b: 1 < b - a)(xs)
|
|
])
|
|
|
|
|
|
# rangeString :: [Int] -> String
|
|
def rangeString(xs):
|
|
'''Start and end of xs delimited by hyphens
|
|
if there are more than two integers.
|
|
Otherwise, comma-delimited xs.
|
|
'''
|
|
ys = [str(x) for x in xs]
|
|
return '-'.join([ys[0], ys[-1]]) if 2 < len(ys) else (
|
|
','.join(ys)
|
|
)
|
|
|
|
|
|
# TEST ----------------------------------------------------
|
|
# main :: IO ()
|
|
def main():
|
|
'''Test'''
|
|
|
|
xs = [
|
|
0, 1, 2, 4, 6, 7, 8, 11, 12, 14,
|
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
|
25, 27, 28, 29, 30, 31, 32, 33, 35, 36,
|
|
37, 38, 39
|
|
]
|
|
print(
|
|
__doc__ + ':\n[' + '\n'.join(map(
|
|
lambda x: ' ' + repr(x)[1:-1],
|
|
chunksOf(11)(xs)
|
|
)) + " ]\n\n -> '" + rangeFormat(xs) + "'\n"
|
|
)
|
|
|
|
|
|
# GENERIC -------------------------------------------------
|
|
|
|
# chunksOf :: Int -> [a] -> [[a]]
|
|
def chunksOf(n):
|
|
'''A series of lists of length n,
|
|
subdividing the contents of xs.
|
|
Where the length of xs is not evenly divible,
|
|
the final list will be shorter than n.'''
|
|
return lambda xs: reduce(
|
|
lambda a, i: a + [xs[i:n + i]],
|
|
range(0, len(xs), n), []
|
|
) if 0 < n else []
|
|
|
|
|
|
# splitBy :: (a -> a -> Bool) -> [a] -> [[a]]
|
|
def splitBy(p):
|
|
'''A list split wherever two consecutive
|
|
items match the binary predicate p.
|
|
'''
|
|
# step :: ([[a]], [a], a) -> a -> ([[a]], [a], a)
|
|
def step(acp, x):
|
|
acc, active, prev = acp
|
|
return (acc + [active], [x], x) if p(prev, x) else (
|
|
(acc, active + [x], x)
|
|
)
|
|
|
|
# go :: [a] -> [[a]]
|
|
def go(xs):
|
|
if 2 > len(xs):
|
|
return xs
|
|
else:
|
|
h = xs[0]
|
|
ys = reduce(step, xs[1:], ([], [h], h))
|
|
# The accumulated sublists, and the current group.
|
|
return ys[0] + [ys[1]]
|
|
|
|
return lambda xs: go(xs)
|
|
|
|
|
|
# MAIN ---
|
|
if __name__ == '__main__':
|
|
main()
|