Skip to content

Instantly share code, notes, and snippets.

@bitwombat
Last active July 23, 2019 04:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bitwombat/ff2024aa036059378829ceea68996995 to your computer and use it in GitHub Desktop.
Save bitwombat/ff2024aa036059378829ceea68996995 to your computer and use it in GitHub Desktop.
Calculate the frequency of letters, via generic Python
'''Character counting as a fold'''
from functools import reduce
from itertools import repeat
from os.path import expanduser
# charCounts :: String -> Dict Char Int
def charCounts(s):
'''A dictionary of
(character, frequency) mappings
'''
def tally(dct, c):
dct[c] = 1 + dct[c] if c in dct else 1
return dct
return reduce(tally, list(s), {})
# TEST ----------------------------------------------------
# main :: IO ()
def main():
'''Listing in descending order of frequency.'''
print(
tabulated(
'Descending order of frequency:\n'
)(compose(repr)(fst))(compose(str)(snd))(
5
)(stet)(
sorted(
charCounts(
readFile('~/Code/charCount/readme.txt')
).items(),
key=swap,
reverse=True
)
)
)
# 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 []
# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
'''Right to left function composition.'''
return lambda f: lambda x: g(f(x))
# fst :: (a, b) -> a
def fst(tpl):
'''First member of a pair.'''
return tpl[0]
# 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()
# paddedMatrix :: a -> [[a]] -> [[a]]
def paddedMatrix(v):
''''A list of rows padded to equal length
(where needed) with instances of the value v.'''
def go(rows):
return paddedRows(
len(max(rows, key=len))
)(v)(rows)
return lambda rows: go(rows) if rows else []
# paddedRows :: Int -> a -> [[a]] -[[a]]
def paddedRows(n):
'''A list of rows padded (but never truncated)
to length n with copies of value v.'''
def go(v, xs):
def pad(x):
d = n - len(x)
return (x + list(repeat(v, d))) if 0 < d else x
return list(map(pad, xs))
return lambda v: lambda xs: go(v, xs) if xs else []
# showColumns :: Int -> [String] -> String
def showColumns(n):
'''A column-wrapped string
derived from a list of rows.'''
def go(xs):
def fit(col):
w = len(max(col, key=len))
def pad(x):
return x.ljust(4 + w, ' ')
return ''.join(map(pad, col)).rstrip()
q, r = divmod(len(xs), n)
return '\n'.join(map(
fit,
zip(*paddedMatrix('')(
chunksOf(q + int(bool(r)))(xs)
))
))
return lambda xs: go(xs)
# snd :: (a, b) -> b
def snd(tpl):
'''Second member of a pair.'''
return tpl[1]
# stet :: a -> a
def stet(x):
'''The identity function.
The usual 'id' is reserved in Python.'''
return x
# swap :: (a, b) -> (b, a)
def swap(tpl):
'''The swapped components of a pair.'''
return (tpl[1], tpl[0])
# tabulated :: String -> (a -> String) ->
# (b -> String) ->
# Int ->
# (a -> b) -> [a] -> String
def tabulated(s):
'''Heading -> x display function -> fx display function ->
number of columns -> f -> value list -> tabular string.'''
def go(xShow, fxShow, intCols, f, xs):
def mxw(fshow, g):
return max(map(compose(len)(fshow), map(g, xs)))
w = mxw(xShow, lambda x: x)
fw = mxw(fxShow, f)
return s + '\n' + showColumns(intCols)([
xShow(x).rjust(w, ' ') + ' -> ' + (
fxShow(f(x)).rjust(fw, ' ')
)
for x in xs
])
return lambda xShow: lambda fxShow: lambda nCols: (
lambda f: lambda xs: go(
xShow, fxShow, nCols, f, xs
)
)
# MAIN ---
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment