RosettaCodeData/Task/Tau-number/Python/tau-number-2.py

131 lines
2.7 KiB
Python

'''Tau numbers'''
from operator import mul
from math import floor, sqrt
from functools import reduce
from itertools import (
accumulate, chain, count,
groupby, islice, product
)
# tauNumbers :: Generator [Int]
def tauNumbers():
'''Positive integers divisible by the
count of their positive divisors.
'''
return (
n for n in count(1)
if 0 == n % len(divisors(n))
)
# ------------------------- TEST -------------------------
# main :: IO ()
def main():
'''The first hundred Tau numbers.
'''
xs = take(100)(
tauNumbers()
)
w = len(str(xs[-1]))
print('\n'.join([
' '.join([
str(cell).rjust(w, ' ') for cell in row
])
for row in chunksOf(10)(xs)
]))
# ----------------------- 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.
'''
def go(xs):
return (
xs[i:n + i] for i in range(0, len(xs), n)
) if 0 < n else None
return go
# divisors :: Int -> [Int]
def divisors(n):
'''The ordered divisors of n.
'''
def go(a, x):
return [a * b for a, b in product(
a,
accumulate(chain([1], x), mul)
)]
return sorted(
reduce(go, [
list(g) for _, g
in groupby(primeFactors(n))
], [1])
) if 1 < n else [1]
# primeFactors :: Int -> [Int]
def primeFactors(n):
'''A list of the prime factors of n.
'''
def f(qr):
r = qr[1]
return step(r), 1 + r
def step(x):
return 1 + (x << 2) - ((x >> 1) << 1)
def go(x):
root = floor(sqrt(x))
def p(qr):
q = qr[0]
return root < q or 0 == (x % q)
q = until(p)(f)(
(2 if 0 == x % 2 else 3, 1)
)[0]
return [x] if q > root else [q] + go(x // q)
return go(n)
# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
'''The prefix of xs of length n,
or xs itself if n > length xs.
'''
def go(xs):
return (
xs[0:n]
if isinstance(xs, (list, tuple))
else list(islice(xs, n))
)
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()