RosettaCodeData/Task/Abbreviations-automatic/Python/abbreviations-automatic-3.py

125 lines
2.8 KiB
Python

'''Automatic abbreviations'''
from itertools import (accumulate, chain)
from os.path import expanduser
# abbrevLen :: [String] -> Int
def abbrevLen(xs):
'''The minimum length of prefix required to obtain
a unique abbreviation for each string in xs.'''
n = len(xs)
return next(
len(a[0]) for a in map(
compose(nub)(map_(concat)),
transpose(list(map(inits, xs)))
) if n == len(a)
)
# TEST ----------------------------------------------------
def main():
'''Test'''
xs = map_(strip)(
lines(readFile('weekDayNames.txt'))
)
for i, n in enumerate(map(compose(abbrevLen)(words), xs)):
print(n, ' ', xs[i])
# GENERIC -------------------------------------------------
# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
'''Function composition.'''
return lambda f: lambda x: g(f(x))
# concat :: [String] -> String
def concat(xs):
'''The concatenation of a list of strings.'''
return ''.join(xs)
# inits :: [a] -> [[a]]
def inits(xs):
'''all initial segments of xs, shortest first.'''
return list(scanl(lambda a, x: a + [x])(
[]
)(list(xs)))
# lines :: String -> [String]
def lines(s):
'''A list of strings,
(containing no newline characters)
derived from a single new-line delimited string.'''
return s.splitlines()
# map :: (a -> b) -> [a] -> [b]
def map_(f):
'''The list obtained by applying f
to each element of xs.'''
return lambda xs: list(map(f, xs))
# nub :: [a] -> [a]
def nub(xs):
'''A list containing the same elements as xs,
without duplicates, in the order of their
first occurrence.'''
return list(dict.fromkeys(xs))
# readFile :: FilePath -> IO String
def readFile(fp):
'''The contents of any file at the path
derived by expanding any ~ in fp.'''
with open(expanduser(fp), 'r', encoding='utf-8') as f:
return f.read()
# scanl :: (b -> a -> b) -> b -> [a] -> [b]
def scanl(f):
'''scanl is like reduce, but returns a succession of
intermediate values, building from the left.'''
return lambda a: lambda xs: (
accumulate(chain([a], xs), f)
)
# strip :: String -> String
def strip(s):
'''A copy of s without any leading or trailling
white space.'''
return s.strip()
# transpose :: Matrix a -> Matrix a
def transpose(m):
'''The rows and columns of the argument transposed.
(The matrix containers and rows can be lists or tuples).'''
if m:
inner = type(m[0])
z = zip(*m)
return (type(m))(
map(inner, z) if tuple != inner else z
)
else:
return m
# words :: String -> [String]
def words(s):
'''A list of words delimited by characters
representing white space.'''
return s.split()
# MAIN ---
if __name__ == '__main__':
main()