Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
198
Task/Teacup-rim-text/Python/teacup-rim-text.py
Normal file
198
Task/Teacup-rim-text/Python/teacup-rim-text.py
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
'''Teacup rim text'''
|
||||
|
||||
from itertools import chain, groupby
|
||||
from os.path import expanduser
|
||||
from functools import reduce
|
||||
|
||||
|
||||
# main :: IO ()
|
||||
def main():
|
||||
'''Circular anagram groups, of more than one word,
|
||||
and containing words of length > 2, found in:
|
||||
https://www.mit.edu/~ecprice/wordlist.10000
|
||||
'''
|
||||
print('\n'.join(
|
||||
concatMap(circularGroup)(
|
||||
anagrams(3)(
|
||||
# Reading from a local copy.
|
||||
lines(readFile('~/mitWords.txt'))
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
|
||||
# anagrams :: Int -> [String] -> [[String]]
|
||||
def anagrams(n):
|
||||
'''Groups of anagrams, of minimum group size n,
|
||||
found in the given word list.
|
||||
'''
|
||||
def go(ws):
|
||||
def f(xs):
|
||||
return [
|
||||
[snd(x) for x in xs]
|
||||
] if n <= len(xs) >= len(xs[0][0]) else []
|
||||
return concatMap(f)(groupBy(fst)(sorted(
|
||||
[(''.join(sorted(w)), w) for w in ws],
|
||||
key=fst
|
||||
)))
|
||||
return go
|
||||
|
||||
|
||||
# circularGroup :: [String] -> [String]
|
||||
def circularGroup(ws):
|
||||
'''Either an empty list, or a list containing
|
||||
a string showing any circular subset found in ws.
|
||||
'''
|
||||
lex = set(ws)
|
||||
iLast = len(ws) - 1
|
||||
# If the set contains one word that is circular,
|
||||
# then it must contain all of them.
|
||||
(i, blnCircular) = until(
|
||||
lambda tpl: tpl[1] or (tpl[0] > iLast)
|
||||
)(
|
||||
lambda tpl: (1 + tpl[0], isCircular(lex)(ws[tpl[0]]))
|
||||
)(
|
||||
(0, False)
|
||||
)
|
||||
return [' -> '.join(allRotations(ws[i]))] if blnCircular else []
|
||||
|
||||
|
||||
# isCircular :: Set String -> String -> Bool
|
||||
def isCircular(lexicon):
|
||||
'''True if all of a word's rotations
|
||||
are found in the given lexicon.
|
||||
'''
|
||||
def go(w):
|
||||
def f(tpl):
|
||||
(i, _, x) = tpl
|
||||
return (1 + i, x in lexicon, rotated(x))
|
||||
|
||||
iLast = len(w) - 1
|
||||
return until(
|
||||
lambda tpl: iLast < tpl[0] or (not tpl[1])
|
||||
)(f)(
|
||||
(0, True, rotated(w))
|
||||
)[1]
|
||||
return go
|
||||
|
||||
|
||||
# allRotations :: String -> [String]
|
||||
def allRotations(w):
|
||||
'''All rotations of the string w.'''
|
||||
return takeIterate(len(w) - 1)(
|
||||
rotated
|
||||
)(w)
|
||||
|
||||
|
||||
# GENERIC -------------------------------------------------
|
||||
|
||||
# concatMap :: (a -> [b]) -> [a] -> [b]
|
||||
def concatMap(f):
|
||||
'''A concatenated list over which a function has been mapped.
|
||||
The list monad can be derived by using a function f which
|
||||
wraps its output in a list,
|
||||
(using an empty list to represent computational failure).
|
||||
'''
|
||||
def go(xs):
|
||||
return chain.from_iterable(map(f, xs))
|
||||
return go
|
||||
|
||||
|
||||
# fst :: (a, b) -> a
|
||||
def fst(tpl):
|
||||
'''First member of a pair.'''
|
||||
return tpl[0]
|
||||
|
||||
|
||||
# groupBy :: (a -> b) -> [a] -> [[a]]
|
||||
def groupBy(f):
|
||||
'''The elements of xs grouped,
|
||||
preserving order, by equality
|
||||
in terms of the key function f.
|
||||
'''
|
||||
def go(xs):
|
||||
return [
|
||||
list(x[1]) for x in groupby(xs, key=f)
|
||||
]
|
||||
return go
|
||||
|
||||
|
||||
# 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()
|
||||
|
||||
|
||||
# mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
|
||||
def mapAccumL(f):
|
||||
'''A tuple of an accumulation and a list derived by a
|
||||
combined map and fold,
|
||||
with accumulation from left to right.
|
||||
'''
|
||||
def go(a, x):
|
||||
tpl = f(a[0], x)
|
||||
return (tpl[0], a[1] + [tpl[1]])
|
||||
return lambda acc: lambda xs: (
|
||||
reduce(go, xs, (acc, []))
|
||||
)
|
||||
|
||||
|
||||
# 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()
|
||||
|
||||
|
||||
# rotated :: String -> String
|
||||
def rotated(s):
|
||||
'''A string rotated 1 character to the right.'''
|
||||
return s[1:] + s[0]
|
||||
|
||||
|
||||
# snd :: (a, b) -> b
|
||||
def snd(tpl):
|
||||
'''Second member of a pair.'''
|
||||
return tpl[1]
|
||||
|
||||
|
||||
# takeIterate :: Int -> (a -> a) -> a -> [a]
|
||||
def takeIterate(n):
|
||||
'''Each value of n iterations of f
|
||||
over a start value of x.
|
||||
'''
|
||||
def go(f):
|
||||
def g(x):
|
||||
def h(a, i):
|
||||
v = f(a) if i else x
|
||||
return (v, v)
|
||||
return mapAccumL(h)(x)(
|
||||
range(0, 1 + n)
|
||||
)[1]
|
||||
return g
|
||||
return go
|
||||
|
||||
|
||||
# until :: (a -> Bool) -> (a -> a) -> a -> a
|
||||
def until(p):
|
||||
'''The result of repeatedly applying f until p holds.
|
||||
The initial seed value is x.
|
||||
'''
|
||||
def go(f):
|
||||
def g(x):
|
||||
v = x
|
||||
while not p(v):
|
||||
v = f(v)
|
||||
return v
|
||||
return g
|
||||
return go
|
||||
|
||||
|
||||
# MAIN ---
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue