Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
86
Task/Esthetic-numbers/Python/esthetic-numbers-1.py
Normal file
86
Task/Esthetic-numbers/Python/esthetic-numbers-1.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
from collections import deque
|
||||
from itertools import dropwhile, islice, takewhile
|
||||
from textwrap import wrap
|
||||
from typing import Iterable, Iterator
|
||||
|
||||
|
||||
Digits = str # Alias for the return type of to_digits()
|
||||
|
||||
|
||||
def esthetic_nums(base: int) -> Iterator[int]:
|
||||
"""Generate the esthetic number sequence for a given base
|
||||
|
||||
>>> list(islice(esthetic_nums(base=10), 20))
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 21, 23, 32, 34, 43, 45, 54, 56, 65]
|
||||
"""
|
||||
queue: deque[tuple[int, int]] = deque()
|
||||
queue.extendleft((d, d) for d in range(1, base))
|
||||
while True:
|
||||
num, lsd = queue.pop()
|
||||
yield num
|
||||
new_lsds = (d for d in (lsd - 1, lsd + 1) if 0 <= d < base)
|
||||
num *= base # Shift num left one digit
|
||||
queue.extendleft((num + d, d) for d in new_lsds)
|
||||
|
||||
|
||||
def to_digits(num: int, base: int) -> Digits:
|
||||
"""Return a representation of an integer as digits in a given base
|
||||
|
||||
>>> to_digits(0x3def84f0ce, base=16)
|
||||
'3def84f0ce'
|
||||
"""
|
||||
digits: list[str] = []
|
||||
while num:
|
||||
num, d = divmod(num, base)
|
||||
digits.append("0123456789abcdef"[d])
|
||||
return "".join(reversed(digits)) if digits else "0"
|
||||
|
||||
|
||||
def pprint_it(it: Iterable[str], indent: int = 4, width: int = 80) -> None:
|
||||
"""Pretty print an iterable which returns strings
|
||||
|
||||
>>> pprint_it(map(str, range(20)), indent=0, width=40)
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19
|
||||
<BLANKLINE>
|
||||
"""
|
||||
joined = ", ".join(it)
|
||||
lines = wrap(joined, width=width - indent)
|
||||
for line in lines:
|
||||
print(f"{indent*' '}{line}")
|
||||
print()
|
||||
|
||||
|
||||
def task_2() -> None:
|
||||
nums: Iterator[int]
|
||||
for base in range(2, 16 + 1):
|
||||
start, stop = 4 * base, 6 * base
|
||||
nums = esthetic_nums(base)
|
||||
nums = islice(nums, start - 1, stop) # start and stop are 1-based indices
|
||||
print(
|
||||
f"Base-{base} esthetic numbers from "
|
||||
f"index {start} through index {stop} inclusive:\n"
|
||||
)
|
||||
pprint_it(to_digits(num, base) for num in nums)
|
||||
|
||||
|
||||
def task_3(lower: int, upper: int, base: int = 10) -> None:
|
||||
nums: Iterator[int] = esthetic_nums(base)
|
||||
nums = dropwhile(lambda num: num < lower, nums)
|
||||
nums = takewhile(lambda num: num <= upper, nums)
|
||||
print(
|
||||
f"Base-{base} esthetic numbers with "
|
||||
f"magnitude between {lower:,} and {upper:,}:\n"
|
||||
)
|
||||
pprint_it(to_digits(num, base) for num in nums)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("======\nTask 2\n======\n")
|
||||
task_2()
|
||||
|
||||
print("======\nTask 3\n======\n")
|
||||
task_3(1_000, 9_999)
|
||||
|
||||
print("======\nTask 4\n======\n")
|
||||
task_3(100_000_000, 130_000_000)
|
||||
256
Task/Esthetic-numbers/Python/esthetic-numbers-2.py
Normal file
256
Task/Esthetic-numbers/Python/esthetic-numbers-2.py
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
'''Esthetic numbers'''
|
||||
|
||||
from functools import reduce
|
||||
from itertools import (
|
||||
accumulate, chain, count, dropwhile,
|
||||
islice, product, takewhile
|
||||
)
|
||||
from operator import add
|
||||
from string import digits, ascii_lowercase
|
||||
from textwrap import wrap
|
||||
|
||||
|
||||
# estheticNumbersInBase :: Int -> [Int]
|
||||
def estheticNumbersInBase(b):
|
||||
'''Infinite stream of numbers which are
|
||||
esthetic in a given base.
|
||||
'''
|
||||
return concatMap(
|
||||
compose(
|
||||
lambda deltas: concatMap(
|
||||
lambda headDigit: concatMap(
|
||||
compose(
|
||||
fromBaseDigits(b),
|
||||
scanl(add)(headDigit)
|
||||
)
|
||||
)(deltas)
|
||||
)(range(1, b)),
|
||||
replicateList([-1, 1])
|
||||
)
|
||||
)(count(0))
|
||||
|
||||
|
||||
# ------------------------ TESTS -------------------------
|
||||
def main():
|
||||
'''Specified tests'''
|
||||
def samples(b):
|
||||
i, j = b * 4, b * 6
|
||||
return '\n'.join([
|
||||
f'Esthetics [{i}..{j}] for base {b}:',
|
||||
unlines(wrap(
|
||||
unwords([
|
||||
showInBase(b)(n) for n in compose(
|
||||
drop(i - 1), take(j)
|
||||
)(
|
||||
estheticNumbersInBase(b)
|
||||
)
|
||||
]), 60
|
||||
))
|
||||
])
|
||||
|
||||
def takeInRange(a, b):
|
||||
return compose(
|
||||
dropWhile(lambda x: x < a),
|
||||
takeWhile(lambda x: x <= b)
|
||||
)
|
||||
|
||||
print(
|
||||
'\n\n'.join([
|
||||
samples(b) for b in range(2, 1 + 16)
|
||||
])
|
||||
)
|
||||
for (lo, hi) in [(1000, 9999), (100_000_000, 130_000_000)]:
|
||||
print(f'\nBase 10 Esthetics in range [{lo}..{hi}]:')
|
||||
print(
|
||||
unlines(wrap(
|
||||
unwords(
|
||||
str(x) for x in takeInRange(lo, hi)(
|
||||
estheticNumbersInBase(10)
|
||||
)
|
||||
), 60
|
||||
))
|
||||
)
|
||||
|
||||
|
||||
# ------------------- BASES AND DIGITS -------------------
|
||||
|
||||
# fromBaseDigits :: Int -> [Int] -> [Int]
|
||||
def fromBaseDigits(b):
|
||||
'''An empty list if any digits are out of range for
|
||||
the base. Otherwise a list containing an integer.
|
||||
'''
|
||||
def go(digitList):
|
||||
maybeNum = reduce(
|
||||
lambda r, d: None if r is None or (
|
||||
0 > d or d >= b
|
||||
) else r * b + d,
|
||||
digitList, 0
|
||||
)
|
||||
return [] if None is maybeNum else [maybeNum]
|
||||
return go
|
||||
|
||||
|
||||
# toBaseDigits :: Int -> Int -> [Int]
|
||||
def toBaseDigits(b):
|
||||
'''A list of the digits of n in base b.
|
||||
'''
|
||||
def f(x):
|
||||
return None if 0 == x else (
|
||||
divmod(x, b)[::-1]
|
||||
)
|
||||
return lambda n: list(reversed(unfoldr(f)(n)))
|
||||
|
||||
|
||||
# showInBase :: Int -> Int -> String
|
||||
def showInBase(b):
|
||||
'''String representation of n in base b.
|
||||
'''
|
||||
charSet = digits + ascii_lowercase
|
||||
return lambda n: ''.join([
|
||||
charSet[i] for i in toBaseDigits(b)(n)
|
||||
])
|
||||
|
||||
|
||||
# ----------------------- GENERIC ------------------------
|
||||
|
||||
# compose :: ((a -> a), ...) -> (a -> a)
|
||||
def compose(*fs):
|
||||
'''Composition, from right to left,
|
||||
of a series of functions.
|
||||
'''
|
||||
def go(f, g):
|
||||
def fg(x):
|
||||
return f(g(x))
|
||||
return fg
|
||||
return reduce(go, fs, lambda x: x)
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
# drop :: Int -> [a] -> [a]
|
||||
# drop :: Int -> String -> String
|
||||
def drop(n):
|
||||
'''The sublist of xs beginning at
|
||||
(zero-based) index n.
|
||||
'''
|
||||
def go(xs):
|
||||
if isinstance(xs, (list, tuple, str)):
|
||||
return xs[n:]
|
||||
else:
|
||||
take(n)(xs)
|
||||
return xs
|
||||
return go
|
||||
|
||||
|
||||
# dropWhile :: (a -> Bool) -> [a] -> [a]
|
||||
# dropWhile :: (Char -> Bool) -> String -> String
|
||||
def dropWhile(p):
|
||||
'''The suffix remainining after takeWhile p xs.
|
||||
'''
|
||||
return lambda xs: list(
|
||||
dropwhile(p, xs)
|
||||
)
|
||||
|
||||
|
||||
# replicateList :: [a] -> Int -> [[a]]
|
||||
def replicateList(xs):
|
||||
'''All distinct lists of length n that
|
||||
consist of elements drawn from xs.
|
||||
'''
|
||||
def rep(n):
|
||||
def go(x):
|
||||
return [[]] if 1 > x else [
|
||||
([a] + b) for (a, b) in product(
|
||||
xs, go(x - 1)
|
||||
)
|
||||
]
|
||||
return go(n)
|
||||
return rep
|
||||
|
||||
|
||||
# scanl :: (b -> a -> b) -> b -> [a] -> [b]
|
||||
def scanl(f):
|
||||
'''scanl is like reduce, but defines a succession of
|
||||
intermediate values, building from the left.
|
||||
'''
|
||||
def go(a):
|
||||
def g(xs):
|
||||
return accumulate(chain([a], xs), f)
|
||||
return g
|
||||
return go
|
||||
|
||||
|
||||
# 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 list(islice(xs, n))
|
||||
return go
|
||||
|
||||
|
||||
# takeWhile :: (a -> Bool) -> [a] -> [a]
|
||||
# takeWhile :: (Char -> Bool) -> String -> String
|
||||
def takeWhile(p):
|
||||
'''The longest (possibly empty) prefix of xs
|
||||
in which all elements satisfy p.
|
||||
'''
|
||||
return lambda xs: list(
|
||||
takewhile(p, xs)
|
||||
)
|
||||
|
||||
|
||||
# unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
|
||||
def unfoldr(f):
|
||||
'''Dual to reduce or foldr.
|
||||
Where catamorphism reduces a list to a summary value,
|
||||
the anamorphic unfoldr builds a list from a seed value.
|
||||
As long as f returns (a, b) a is prepended to the list,
|
||||
and the residual b is used as the argument for the next
|
||||
application of f.
|
||||
When f returns None, the completed list is returned.
|
||||
'''
|
||||
def go(v):
|
||||
xr = v, v
|
||||
xs = []
|
||||
while True:
|
||||
xr = f(xr[1])
|
||||
if None is not xr:
|
||||
xs.append(xr[0])
|
||||
else:
|
||||
return xs
|
||||
return go
|
||||
|
||||
|
||||
# unlines :: [String] -> String
|
||||
def unlines(xs):
|
||||
'''A single string formed by the intercalation
|
||||
of a list of strings with the newline character.
|
||||
'''
|
||||
return '\n'.join(xs)
|
||||
|
||||
|
||||
# unwords :: [String] -> String
|
||||
def unwords(xs):
|
||||
'''A space-separated string derived
|
||||
from a list of words.
|
||||
'''
|
||||
return ' '.join(xs)
|
||||
|
||||
|
||||
# MAIN ---
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue