Pythagorean quadruples

One form of   '''Pythagorean quadruples'''   is   (for positive integers   '''a''',   '''b''',   '''c''',   and   '''d'''):

::::::::    a2   +   b2   +   c2     =     d2

An example:

::::::::    22   +   32   +   62     =     72

::::: which is:

::::::::    4    +   9    +   36     =     49

;Task:

For positive integers up   '''2,200'''   (inclusive),   for all values of   '''a''',
'''b''',   '''c''',   and   '''d''',
find   (and show here)   those values of   '''d'''   that   ''can't''   be represented.

Show the values of   '''d'''   on one line of output   (optionally with a title).

;Related tasks:
*   [[Euler's sum of powers conjecture]].
*   [[Pythagorean triples]].

;Reference:
:*   the Wikipedia article:   Pythagorean quadruple.

Solution:
def quad(top=2200):
    r = [False] * top
    ab = [False] * (top * 2)**2
    for a in range(1, top):
        for b in range(a, top):
            ab[a * a + b * b] = True
    s = 3
    for c in range(1, top):
        s1, s, s2 = s, s + 2, s + 2
        for d in range(c + 1, top):
            if ab[s1]:
                r[d] = True
            s1 += s2
            s2 += 2
    return [i for i, val in enumerate(r) if not val and i]

if __name__ == '__main__':
    n = 2200
    print(f"Those values of d in 1..{n} that can't be represented: {quad(n)}")


Pythagorean quadruples

Solution:
'''Pythagorean Quadruples'''

from itertools import islice, takewhile

# unrepresentables :: () -> [Int]
def unrepresentables():
    '''A non-finite stream of powers of two which can
       not be represented as a Pythagorean quadruple.
    '''
    return merge(
        powersOfTwo()
    )(
        5 * x for x in powersOfTwo()
    )

# powersOfTwo :: Gen [Int]
def powersOfTwo():
    '''A non-finite stream of successive powers of two.
    '''
    def double(x):
        return 2 * x

    return iterate(double)(1)

# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''For positive integers up to 2,200 (inclusive)
    '''
    def p(x):
        return 2200 >= x

    print(
        list(
            takewhile(p, unrepresentables())
        )
    )

# ----------------------- GENERIC ------------------------

# iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
    '''An infinite list of repeated
       applications of f to x.
    '''
    def go(x):
        v = x
        while True:
            yield v
            v = f(v)
    return go

# merge :: Gen [Int] -> Gen [Int] -> Gen [Int]
def merge(ga):
    '''An ordered stream of values drawn from two
       other ordered streams.
    '''
    def go(gb):
        def f(ma, mb):
            a, b = ma, mb
            while a and b:
                ta, tb = a, b
                if ta[0] < tb[0]:
                    yield ta[0]
                    a = uncons(ta[1])
                else:
                    yield tb[0]
                    b = uncons(tb[1])
        return f(uncons(ga), uncons(gb))
    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 (
            xs[0:n]
            if isinstance(xs, (list, tuple))
            else list(islice(xs, n))
        )
    return go

# uncons :: [a] -> Maybe (a, [a])
def uncons(xs):
    '''The deconstruction of a non-empty list
       (or generator stream) into two parts:
       a head value, and the remaining values.
    '''
    if isinstance(xs, list):
        return (xs[0], xs[1:]) if xs else None
    else:
        nxt = take(1)(xs)
        return (nxt[0], xs) if nxt else None

# MAIN ---
if __name__ == '__main__':
    main()


Pythagorean triples

A Pythagorean triple is defined as three positive integers (a, b, c) where a < b < c, and a^2+b^2=c^2.

They are called primitive triples if a, b, c are co-prime, that is, if their pairwise greatest common divisors {\rm gcd}(a, b) = {\rm gcd}(a, c) = {\rm gcd}(b, c) = 1.

Because of their relationship through the Pythagorean theorem, a, b, and c are co-prime if a and b are co-prime ({\rm gcd}(a, b) = 1).

Each triple forms the length of the sides of a right triangle, whose perimeter is P=a+b+c.

;Task:
The task is to determine how many Pythagorean triples there are with a perimeter no larger than 100 and the number of these that are primitive.

;Extra credit:
Deal with large values.   Can your program handle a maximum perimeter of 1,000,000?   What about 10,000,000?   100,000,000?

Note: the extra credit is not for you to demonstrate how fast your language is compared to others;   you need a proper algorithm to solve them in a timely manner.

;Related tasks:
*   [[Euler's sum of powers conjecture]]
*   [[List comprehensions]]
*   [[Pythagorean quadruples]]

Solution:
from fractions import gcd

def pt1(maxperimeter=100):
    '''
# Naive method
    '''
    trips = []
    for a in range(1, maxperimeter):
        aa = a*a
        for b in range(a, maxperimeter-a+1):
            bb = b*b
            for c in range(b, maxperimeter-b-a+1):
                cc = c*c
                if a+b+c > maxperimeter or cc > aa + bb: break
                if aa + bb == cc:
                    trips.append((a,b,c, gcd(a, b) == 1))
    return trips

def pytrip(trip=(3,4,5),perim=100, prim=1):
    a0, b0, c0 = a, b, c = sorted(trip)
    t, firstprim = set(), prim>0
    while a + b + c <= perim:
        t.add((a, b, c, firstprim>0))
        a, b, c, firstprim = a+a0, b+b0, c+c0, False
    #
    t2 = set()
    for a, b, c, firstprim in t:
        a2, a5, b2, b5, c2, c3, c7 = a*2, a*5, b*2, b*5, c*2, c*3, c*7
        if  a5 - b5 + c7 <= perim:
            t2 |= pytrip(( a - b2 + c2,  a2 - b + c2,  a2 - b2 + c3), perim, firstprim)
        if  a5 + b5 + c7 <= perim:
            t2 |= pytrip(( a + b2 + c2,  a2 + b + c2,  a2 + b2 + c3), perim, firstprim)
        if -a5 + b5 + c7 <= perim:
            t2 |= pytrip((-a + b2 + c2, -a2 + b + c2, -a2 + b2 + c3), perim, firstprim)
    return t | t2

def pt2(maxperimeter=100):
    '''
# Parent/child relationship method:
# http://en.wikipedia.org/wiki/Formulas_for_generating_Pythagorean_triples#XI.
    '''
    trips = pytrip((3,4,5), maxperimeter, 1)
    return trips

def printit(maxperimeter=100, pt=pt1):
    trips = pt(maxperimeter)
    print("  Up to a perimeter of %i there are %i triples, of which %i are primitive"
          % (maxperimeter,
             len(trips),
             len([prim for a,b,c,prim in trips if prim])))

for algo, mn, mx in ((pt1, 250, 2500), (pt2, 500, 20000)):
    print(algo.__doc__)
    for maxperimeter in range(mn, mx+1, mn):
        printit(maxperimeter, algo)


Quaternion type

complex numbers.

A complex number has a real and complex part,   sometimes written as     a + bi,
where     a     and     b     stand for real numbers, and     i     stands for the square root of minus 1.

An example of a complex number might be     -3 + 2i,
where the real part,     a     is     '''-3.0'''     and the complex part,     b     is     '''+2.0'''.

A quaternion has one real part and ''three'' imaginary parts,     i,       j,     and     k.

A quaternion might be written as     a + bi + cj + dk.

In the quaternion numbering system:
:::*     ii = jj = kk = ijk = -1,         or more simply,
:::*     ii  = jj  = kk  = ijk   = -1.

The order of multiplication is important, as, in general, for two quaternions:
::::     q1     and     q2:         q1q2  q2q1.

An example of a quaternion might be     1 +2i +3j +4k

There is a list form of notation where just the numbers are shown and the imaginary multipliers    i,       j,     and     k     are assumed by position.

So the example above would be written as     (1, 2, 3, 4)

;Task:
Given the three quaternions and their components:
    q  = (1, 2, 3, 4) = (a,  b,  c,  d)
    q1 = (2, 3, 4, 5) = (a1, b1, c1, d1)
    q2 = (3, 4, 5, 6) = (a2, b2, c2, d2)
And a wholly real number     r = 7.

Create functions   (or classes)   to perform simple maths with quaternions including computing:
# The norm of a quaternion: = \sqrt{a^2 + b^2 + c^2 + d^2}
# The negative of a quaternion:    = (-a, -b, -c, -d)
# The conjugate of a quaternion:    = ( a, -b, -c, -d)
# Addition of a real number     r     and a quaternion     q:      r + q = q + r = (a+r, b, c, d)
# Addition of two quaternions:    q1 + q2 = (a1+a2, b1+b2, c1+c2, d1+d2)
# Multiplication of a real number and a quaternion:    qr = rq = (ar, br, cr, dr)
# Multiplication of two quaternions     q1     and   q2     is given by:    ( a1a2 - b1b2 - c1c2 - d1d2,      a1b2 + b1a2 + c1d2 - d1c2,      a1c2 - b1d2 + c1a2 + d1b2,      a1d2 + b1c2 - c1b2 + d1a2 )
# Show that, for the two quaternions     q1     and     q2:  q1q2  q2q1

If a language has built-in support for quaternions, then use it.

;C.f.:
*   [[Vector products]]
*   On Quaternions;   or on a new System of Imaginaries in Algebra.   By Sir William Rowan Hamilton LL.D, P.R.I.A., F.R.A.S., Hon. M. R. Soc. Ed. and Dub., Hon. or Corr. M. of the Royal or Imperial Academies of St. Petersburgh, Berlin, Turin and Paris, Member of the American Academy of Arts and Sciences, and of other Scientific Societies at Home and Abroad, Andrews' Prof. of Astronomy in the University of Dublin, and Royal Astronomer of Ireland.

Solution:
from collections import namedtuple
import math

class Q(namedtuple('Quaternion', 'real, i, j, k')):
    'Quaternion type: Q(real=0.0, i=0.0, j=0.0, k=0.0)'

    __slots__ = ()

    def __new__(_cls, real=0.0, i=0.0, j=0.0, k=0.0):
        'Defaults all parts of quaternion to zero'
        return super().__new__(_cls, float(real), float(i), float(j), float(k))

    def conjugate(self):
        return Q(self.real, -self.i, -self.j, -self.k)

    def _norm2(self):
        return sum( x*x for x in self)

    def norm(self):
        return math.sqrt(self._norm2())

    def reciprocal(self):
        n2 = self._norm2()
        return Q(*(x / n2 for x in self.conjugate()))

    def __str__(self):
        'Shorter form of Quaternion as string'
        return 'Q(%g, %g, %g, %g)' % self

    def __neg__(self):
        return Q(-self.real, -self.i, -self.j, -self.k)

    def __add__(self, other):
        if type(other) == Q:
            return Q( *(s+o for s,o in zip(self, other)) )
        try:
            f = float(other)
        except:
            return NotImplemented
        return Q(self.real + f, self.i, self.j, self.k)

    def __radd__(self, other):
        return Q.__add__(self, other)

    def __mul__(self, other):
        if type(other) == Q:
            a1,b1,c1,d1 = self
            a2,b2,c2,d2 = other
            return Q(
                 a1*a2 - b1*b2 - c1*c2 - d1*d2,
                 a1*b2 + b1*a2 + c1*d2 - d1*c2,
                 a1*c2 - b1*d2 + c1*a2 + d1*b2,
                 a1*d2 + b1*c2 - c1*b2 + d1*a2 )
        try:
            f = float(other)
        except:
            return NotImplemented
        return Q(self.real * f, self.i * f, self.j * f, self.k * f)

    def __rmul__(self, other):
        return Q.__mul__(self, other)

    def __truediv__(self, other):
        if type(other) == Q:
            return self.__mul__(other.reciprocal())
        try:
            f = float(other)
        except:
            return NotImplemented
        return Q(self.real / f, self.i / f, self.j / f, self.k / f)

    def __rtruediv__(self, other):
        return other * self.reciprocal()

    __div__, __rdiv__ = __truediv__, __rtruediv__

Quaternion = Q

q  = Q(1, 2, 3, 4)
q1 = Q(2, 3, 4, 5)
q2 = Q(3, 4, 5, 6)
r  = 7


Quine

A quine is a self-referential program that can,
without any external access, output its own source.

A   '''quine'''   (named after Willard Van Orman Quine)   is also known as:
::*   ''self-reproducing automata''        (1972)
::*   ''self-replicating program''                             or   ''self-replicating computer program''
::*   ''self-reproducing program''                                  or   ''self-reproducing computer program''
::*   ''self-copying program''                       or   ''self-copying computer program''

It is named after the philosopher and logician
who studied self-reference and quoting in natural language,
as for example in the paradox "'Yields falsehood when preceded by its quotation' yields falsehood when preceded by its quotation."

"Source" has one of two meanings. It can refer to the text-based program source.
For languages in which program source is represented as a data structure, "source" may refer to the data structure: quines in these languages fall into two categories: programs which print a textual representation of themselves, or expressions which evaluate to a data structure which is equivalent to that expression.

The usual way to code a quine works similarly to this paradox: The program consists of two identical parts, once as plain code and once ''quoted'' in some way (for example, as a character string, or a literal data structure). The plain code then accesses the quoted code and prints it out twice, once unquoted and once with the proper quotation marks added. Often, the plain code and the quoted code have to be nested.

;Task:
Write a program that outputs its own source code in this way. If the language allows it, you may add a variant that accesses the code directly. You are not allowed to read any external files with the source code. The program should also contain some sort of self-reference, so constant expressions which return their own value which some top-level interpreter will print out.  Empty programs producing no output are not allowed.

There are several difficulties that one runs into when writing a quine, mostly dealing with quoting:
* Part of the code usually needs to be stored as a string or structural literal in the language, which needs to be quoted somehow. However, including quotation marks in the string literal itself would be troublesome because it requires them to be escaped, which then necessitates the escaping character (e.g. a backslash) in the string, which itself usually needs to be escaped, and so on.
** Some languages have a function for getting the "source code representation" of a string (i.e. adds quotation marks, etc.); in these languages, this can be used to circumvent the quoting problem.
** Another solution is to construct the quote character from its [[character code]], without having to write the quote character itself. Then the character is inserted into the string at the appropriate places. The ASCII code for double-quote is 34, and for single-quote is 39.
* Newlines in the program may have to be reproduced as newlines in the string, which usually requires some kind of escape sequence (e.g. "\n"). This causes the same problem as above, where the escaping character needs to itself be escaped, etc.
** If the language has a way of getting the "source code representation", it usually handles the escaping of characters, so this is not a problem.
** Some languages allow you to have a string literal that spans multiple lines, which embeds the newlines into the string without escaping.
** Write the entire program on one line, for free-form languages (as you can see for some of the solutions here, they run off the edge of the screen), thus removing the need for newlines. However, this may be unacceptable as some languages require a newline at the end of the file; and otherwise it is still generally good style to have a newline at the end of a file. (The task is not clear on whether a newline is required at the end of the file.) Some languages have a print statement that appends a newline; which solves the newline-at-the-end issue; but others do not.

'''Next to the Quines presented here, many other versions can be found on the Quine page.'''

;Related task:
:*   print itself.

Solution: import sys,inspect;sys.stdout.write(inspect.getsource(inspect.currentframe()))


Quine

Solution:
data = (
	'ZGF0YSA9ICgKCSc=',
	'JywKCSc=',
	'JwopCnByZWZpeCwgc2VwYXJhdG9yLCBzdWZmaXggPSAoZC5kZWNvZGUoJ2Jhc2U2NCcpIGZvciBkIGluIGRhdGEpCnByaW50IHByZWZpeCArIGRhdGFbMF0gKyBzZXBhcmF0b3IgKyBkYXRhWzFdICsgc2VwYXJhdG9yICsgZGF0YVsyXSArIHN1ZmZpeA=='
)
prefix, separator, suffix = (d.decode('base64') for d in data)
print prefix + data[0] + separator + data[1] + separator + data[2] + suffix


RIPEMD-160

'''RIPEMD-160''' is another hash function; it computes a 160-bit message digest.

There is a RIPEMD-160 home page, with test vectors and pseudocode for RIPEMD-160.
For padding the message, RIPEMD-160 acts like [[MD4]] (RFC 1320).

Find the RIPEMD-160 message digest of a string of [[octet]]s.
Use the ASCII encoded string "Rosetta Code".
You may either call an RIPEMD-160 library, or implement RIPEMD-160 in your language.

Solution:
Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import hashlib
>>> h = hashlib.new('ripemd160')
>>> h.update(b"Rosetta Code")
>>> h.hexdigest()
'b3be159860842cebaa7174c8fff0aa9e50a5199f'
>>>


RPG attributes generator

'''RPG'''   =   Role Playing Game.

You're running a tabletop RPG, and your players are creating characters.

Each character has six core attributes: strength, dexterity, constitution, intelligence, wisdom, and charisma.

One way of generating values for these attributes is to roll four, 6-sided dice (d6) and sum the three highest rolls, discarding the lowest roll.

Some players like to assign values to their attributes in the order they're rolled.

To ensure generated characters don't put players at a disadvantage, the following requirements must be satisfied:

* The total of all character attributes must be at least 75.
* At least two of the attributes must be at least 15.

However, this can require a lot of manual dice rolling. A programatic solution would be much faster.

;Task:
Write a program that:
# Generates 4 random, whole values between 1 and 6.
# Saves the sum of the 3 largest values.
# Generates a total of 6 values this way.
# Displays the total, and all 6 values once finished.

* The order in which each value was generated must be preserved.
* The total of all 6 values must be at least 75.
* At least 2 of the values must be 15 or more.

Solution:
import random
random.seed()
attributes_total = 0
count = 0

while attributes_total < 75 or count < 2:
    attributes = []

    for attribute in range(0, 6):
        rolls = []

        for roll in range(0, 4):
            result = random.randint(1, 6)
            rolls.append(result)

        sorted_rolls = sorted(rolls)
        largest_3 = sorted_rolls[1:]
        rolls_total = sum(largest_3)

        if rolls_total >= 15:
            count += 1

        attributes.append(rolls_total)

    attributes_total = sum(attributes)

print(attributes_total, attributes)


RPG attributes generator

Solution:
'''RPG Attributes Generator'''

from itertools import islice
from random import randint
from operator import eq

# heroes :: Gen IO [(Int, Int, Int, Int, Int, Int)]
def heroes(p):
    '''Non-finite list of heroes matching
       the requirements of predicate p.
    '''
    while True:
        yield tuple(
            until(p)(character)([])
        )

# character :: () -> IO [Int]
def character(_):
    '''A random character with six
       integral attributes.
    '''
    return [
        sum(sorted(map(
            randomRInt(1)(6),
            enumFromTo(1)(4)
        ))[1:])
        for _ in enumFromTo(1)(6)
    ]

# ------------------------- TEST --------------------------
# main :: IO ()
def main():
    '''Test :: Sample of 10'''

    # seventyFivePlusWithTwo15s :: [Int] -> Bool
    def seventyFivePlusIncTwo15s(xs):
        '''Sums to 75 or more,
           and includes at least two 15s.
        '''
        return 75 <= sum(xs) and (
            1 < len(list(filter(curry(eq)(15), xs)))
        )

    print('A sample of 10:\n')
    print(unlines(
        str(sum(x)) + ' -> ' + str(x) for x
        in take(10)(heroes(
            seventyFivePlusIncTwo15s
        ))
    ))

# ------------------------- GENERIC -------------------------

# curry :: ((a, b) -> c) -> a -> b -> c
def curry(f):
    '''A curried function derived
       from an uncurried function.
    '''
    return lambda x: lambda y: f(x, y)

# enumFromTo :: Int -> Int -> [Int]
def enumFromTo(m):
    '''Enumeration of integer values [m..n]'''
    return lambda n: range(m, 1 + n)

# randomRInt :: Int -> Int -> IO () -> Int
def randomRInt(m):
    '''The return value of randomRInt is itself
       a function. The returned function, whenever
       called, yields a a new pseudo-random integer
       in the range [m..n].
    '''
    return lambda n: lambda _: randint(m, 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.
    '''
    return lambda xs: (
        xs[0:n]
        if isinstance(xs, (list, tuple))
        else list(islice(xs, n))
    )

# 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)

# 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, x):
        v = x
        while not p(v):
            v = f(v)
        return v
    return lambda f: lambda x: go(f, x)

if __name__ == '__main__':
    main()


Random Latin squares

A Latin square of size n is an arrangement of n symbols  in an n-by-n square in such a way that each row and column has each symbol appearing exactly once.
For the purposes of this task, a random Latin square of size n is a Latin square constructed or generated by a probabilistic procedure such that the probability of any particular Latin square of size n being produced is non-zero.

;Example n=4 randomised Latin square:
0 2 3 1
2 1 0 3
3 0 1 2
1 3 2 0

;Task:
# Create a function/routine/procedure/method/... that given n generates a randomised Latin square of size n.
# Use the function to generate ''and show here'', two randomly generated squares of size 5.

;Note:
Strict ''uniformity'' in the random generation is a hard problem and '''not''' a requirement of the task.

;Related tasks:
* [[Latin Squares in reduced form/Randomizing using Jacobson and Matthews' Technique]]
* [[Latin Squares in reduced form]]

;Reference:
* Wikipedia: Latin square
* OEIS: A002860

Solution:
from random import choice, shuffle
from copy import deepcopy

def rls(n):
    if n <= 0:
        return []
    else:
        symbols = list(range(n))
        square = _rls(symbols)
        return _shuffle_transpose_shuffle(square)

def _shuffle_transpose_shuffle(matrix):
    square = deepcopy(matrix)
    shuffle(square)
    trans = list(zip(*square))
    shuffle(trans)
    return trans

def _rls(symbols):
    n = len(symbols)
    if n == 1:
        return [symbols]
    else:
        sym = choice(symbols)
        symbols.remove(sym)
        square = _rls(symbols)
        square.append(square[0].copy())
        for i in range(n):
            square[i].insert(i, sym)
        return square

def _to_text(square):
    if square:
        width = max(len(str(sym)) for row in square for sym in row)
        txt = '\n'.join(' '.join(f"{sym:>{width}}" for sym in row)
                        for row in square)
    else:
        txt = ''
    return txt

def _check(square):
    transpose = list(zip(*square))
    assert _check_rows(square) and _check_rows(transpose), \
        "Not a Latin square"

def _check_rows(square):
    if not square:
        return True
    set_row0 = set(square[0])
    return all(len(row) == len(set(row)) and set(row) == set_row0
               for row in square)

if __name__ == '__main__':
    for i in [3, 3,  5, 5, 12]:
        square = rls(i)
        print(_to_text(square))
        _check(square)
        print()


Random number generator (device)

If your system has a means to generate random numbers involving not only a software algorithm   (like the /dev/urandom devices in Unix),   then:

show how to obtain a random 32-bit number from that mechanism.

;Related task
* [[Random_number_generator_(included)]]

Solution:
import random
rand = random.SystemRandom()
rand.randint(1,10)


Random number generator (included)

The task is to:
: State the type of random number generator algorithm used in a language's built-in random number generator. If the language or its immediate libraries don't provide a random number generator, skip this task.
: If possible, give a link to a wider explanation of the algorithm used.

Note: the task is ''not'' to create an RNG, but to report on the languages in-built RNG that would be the most likely RNG used.

The main types of pseudo-random number generator (Mersenne twister generator is a subclass). The last main type is where the output of one of the previous ones (typically a Mersenne twister) is fed through a [[cryptographic hash function]] to maximize unpredictability of individual bits.

Note that neither LCGs nor GFSRs should be used for the most demanding applications (cryptography) without additional steps.

Solution: Python uses the [[wp:Mersenne twister|Mersenne twister]] algorithm accessed via the built-in [http://docs.python.org/library/random.html random module].


Random sentence from book

* Read in the book "The War of the Worlds", by H. G. Wells.
* Skip to the start of the book, proper.
* Remove extraneous punctuation, but keep at least sentence-ending punctuation characters . ! and ?
* Keep account of what words follow words and how many times it is seen, (treat sentence terminators as words too).
* Keep account of what words follow ''two'' words and how many times it is seen, (again treating sentence terminators as words too).
* Assume that a sentence starts with a not to be shown full-stop character then ''use a weighted random choice'' of the possible words that may follow a full-stop to add to the sentence.
* Then repeatedly add words to the sentence based on weighted random choices of what words my follow the last two words to extend the sentence.
* Stop after adding a sentence ending punctuation character.
* Tidy and then print the sentence.

Show examples of random sentences generated.

;Related task
* [[Markov_chain_text_generator]]

Solution:
from urllib.request import urlopen
import re
from string import punctuation
from collections import Counter, defaultdict
import random

# The War of the Worlds, by H. G. Wells
text_url = 'http://www.gutenberg.org/files/36/36-0.txt'
text_start = 'No one would have believed'

sentence_ending = '.!?'
sentence_pausing = ',;:'

def read_book(text_url, text_start) -> str:
    with urlopen(text_url) as book:
        text = book.read().decode('utf-8')
    return text[text.index(text_start):]

def remove_punctuation(text: str, keep=sentence_ending+sentence_pausing)-> str:
    "Remove punctuation, keeping some"
    to_remove = ''.join(set(punctuation) - set(keep))
    text = text.translate(str.maketrans(to_remove, ' ' * len(to_remove))).strip()
    text = re.sub(fr"[^a-zA-Z0-9{keep}\n ]+", ' ', text)
    # Remove duplicates and put space around remaining punctuation
    if keep:
        text = re.sub(f"([{keep}])+", r" \1 ", text).strip()
    if text[-1] not in sentence_ending:
        text += ' .'
    return text.lower()

def word_follows_words(txt_with_pauses_and_endings):
    "return dict of freq of words following one/two words"
    words = ['.'] + txt_with_pauses_and_endings.strip().split()

    # count of what word follows this
    word2next = defaultdict(lambda :defaultdict(int))
    word2next2 = defaultdict(lambda :defaultdict(int))
    for lh, rh in zip(words, words[1:]):
        word2next[lh][rh] += 1
    for lh, mid, rh in zip(words, words[1:], words[2:]):
        word2next2[(lh, mid)][rh] += 1

    return dict(word2next), dict(word2next2)

def gen_sentence(word2next, word2next2) -> str:

    s = ['.']
    s += random.choices(*zip(*word2next[s[-1]].items()))
    while True:
        s += random.choices(*zip(*word2next2[(s[-2], s[-1])].items()))
        if s[-1] in sentence_ending:
            break

    s  = ' '.join(s[1:]).capitalize()
    s = re.sub(fr" ([{sentence_ending+sentence_pausing}])", r'\1', s)
    s = re.sub(r" re\b", "'re", s)
    s = re.sub(r" s\b", "'s", s)
    s = re.sub(r"\bi\b", "I", s)

    return s

if __name__ == "__main__":
    txt_with_pauses_and_endings = remove_punctuation(read_book(text_url, text_start))
    word2next, word2next2 = word_follows_words(txt_with_pauses_and_endings)
    #%%
    sentence = gen_sentence(word2next, word2next2)
    print(sentence)


Range consolidation

Define a range of numbers   '''R''',   with bounds   '''b0'''   and   '''b1'''   covering all numbers ''between and including both bounds''.

That range can be shown as:
::::::::: '''[b0, b1]'''
::::::::    or equally as:
::::::::: '''[b1, b0]'''

Given two ranges, the act of consolidation between them compares the two ranges:
*   If one range covers all of the other then the result is that encompassing range.
*   If the ranges touch or intersect then the result is   ''one''   new single range covering the overlapping ranges.
*   Otherwise the act of consolidation is to return the two non-touching ranges.

Given   '''N'''   ranges where   '''N > 2'''   then the result is the same as repeatedly replacing all combinations of two ranges by their consolidation until no further consolidation between range pairs is possible.

If   '''N < 2'''   then range consolidation has no strict meaning and the input can be returned.

;Example 1:
:   Given the two ranges   '''[1, 2.5]'''   and   '''[3, 4.2]'''   then
:   there is no common region between the ranges and the result is the same as the input.

;Example 2:
:   Given the two ranges   '''[1, 2.5]'''   and   '''[1.8, 4.7]'''   then
:   there is :   an overlap   '''[2.5, 1.8]'''   between the ranges and
:   the result is the single range   '''[1, 4.7]'''.
:   Note that order of bounds in a range is not (yet) stated.

;Example 3:
:   Given the two ranges   '''[6.1, 7.2]'''   and   '''[7.2, 8.3]'''   then
:   they touch at   '''7.2'''   and
:   the result is the single range   '''[6.1, 8.3]'''.

;Example 4:
:   Given the three ranges   '''[1, 2]'''   and   '''[4, 8]'''   and   '''[2, 5]'''
:   then there is no intersection of the ranges   '''[1, 2]'''   and   '''[4, 8]'''
:   but the ranges   '''[1, 2]'''   and   '''[2, 5]'''   overlap and
:   consolidate to produce the range   '''[1, 5]'''.
:   This range, in turn, overlaps the other range   '''[4, 8]''',   and
:   so consolidates to the final output of the single range   '''[1, 8]'''.

;Task:
Let a normalized range display show the smaller bound to the left;   and show the
range with the smaller lower bound to the left of other ranges when showing multiple ranges.

Output the ''normalized'' result of applying consolidation to these five sets of ranges:
            [1.1, 2.2]
            [6.1, 7.2], [7.2, 8.3]
            [4, 3], [2, 1]
            [4, 3], [2, 1], [-1, -2], [3.9, 10]
            [1, 3], [-6, -1], [-4, -5], [8, 2], [-6, -6]
Show all output here.

;See also:
* [[Set consolidation]]
* [[Set of real numbers]]

Solution:
def normalize(s):
    return sorted(sorted(bounds) for bounds in s if bounds)

def consolidate(ranges):
    norm = normalize(ranges)
    for i, r1 in enumerate(norm):
        if r1:
            for r2 in norm[i+1:]:
                if r2 and r1[-1] >= r2[0]:     # intersect?
                    r1[:] = [r1[0], max(r1[-1], r2[-1])]
                    r2.clear()
    return [rnge for rnge in norm if rnge]

if __name__ == '__main__':
    for s in [
            [[1.1, 2.2]],
            [[6.1, 7.2], [7.2, 8.3]],
            [[4, 3], [2, 1]],
            [[4, 3], [2, 1], [-1, -2], [3.9, 10]],
            [[1, 3], [-6, -1], [-4, -5], [8, 2], [-6, -6]],
            ]:
        print(f"{str(s)[1:-1]} => {str(consolidate(s))[1:-1]}")


Range consolidation

Solution:
'''Range consolidation'''

from functools import reduce

# consolidated :: [(Float, Float)] -> [(Float, Float)]
def consolidated(xs):
    '''A consolidated list of
       [(Float, Float)] ranges.'''

    def go(abetc, xy):
        '''A copy of the accumulator abetc,
           with its head range ab either:
           1. replaced by or
           2. merged with
           the next range xy, or
           with xy simply prepended.'''
        if abetc:
            a, b = abetc[0]
            etc = abetc[1:]
            x, y = xy
            return [xy] + etc if y >= b else (   # ab replaced.
                [(x, b)] + etc if y >= a else (  # xy + ab merged.
                    [xy] + abetc                 # xy simply prepended.
                )
            )
        else:
            return [xy]

    def tupleSort(ab):
        a, b = ab
        return ab if a <= b else (b, a)

    return reduce(
        go,
        sorted(map(tupleSort, xs), reverse=True),
        []
    )

# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Tests'''

    print(
        tabulated('Consolidation of numeric ranges:')(str)(str)(
            consolidated
        )([
            [(1.1, 2.2)],
            [(6.1, 7.2), (7.2, 8.3)],
            [(4, 3), (2, 1)],
            [(4, 3), (2, 1), (-1, -2), (3.9, 10)],
            [(1, 3), (-6, -1), (-4, -5), (8, 2), (-6, -6)]
        ])
    )

# GENERIC FUNCTIONS FOR DISPLAY ---------------------------

# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
    '''Right to left function composition.'''
    return lambda f: lambda x: g(f(x))

# tabulated :: String -> (a -> String) ->
#                        (b -> String) ->
#                        (a -> b) -> [a] -> String
def tabulated(s):
    '''Heading -> x display function -> fx display function ->
          f -> value list -> tabular string.'''
    def go(xShow, fxShow, f, xs):
        w = max(map(compose(len)(xShow), xs))
        return s + '\n' + '\n'.join([
            xShow(x).rjust(w, ' ') + ' -> ' + fxShow(f(x)) for x in xs
        ])
    return lambda xShow: lambda fxShow: (
        lambda f: lambda xs: go(
            xShow, fxShow, f, xs
        )
    )

# MAIN ---
if __name__ == '__main__':
    main()


Range expansion

{{:Range extraction/Format}}

;Task:
Expand the range description:
   -6,-3--1,3-5,7-11,14,15,17-20
Note that the second element above,
is the '''range from minus 3 to ''minus'' 1'''.

;Related task:
*   [[Range extraction]]

Solution:
def rangeexpand(txt):
    lst = []
    for r in txt.split(','):
        if '-' in r[1:]:
            r0, r1 = r[1:].split('-', 1)
            lst += range(int(r[0] + r0), int(r1) + 1)
        else:
            lst.append(int(r))
    return lst

print(rangeexpand('-6,-3--1,3-5,7-11,14,15,17-20'))


Range expansion

Solution:
'''Range expansion'''

from functools import (reduce)

# ------------------- EXPANSION FUNCTION -------------------

# rangeExpansion :: String -> [Int]
def rangeExpansion(s):
    '''List of integers expanded from a
       comma-delimited string of individual
       numbers and hyphenated ranges.
    '''
    def go(a, x):
        tpl = breakOn('-')(x[1:])
        r = tpl[1]
        return a + (
            [int(x)] if not r
            else enumFromTo(int(x[0] + tpl[0]))(
                int(r[1:])
            )
        )
    return reduce(go, s.split(','), [])

# -------------------------- TEST --------------------------
def main():
    '''Expansion test'''

    print(
        fTable(__doc__ + ':')(
            lambda x: "\n'" + str(x) + "'"
        )(lambda x: '\n\n\t' + showList(x))(
            rangeExpansion
        )([
            '-6,-3--1,3-5,7-11,14,15,17-20'
        ])
    )

# ------------------- GENERIC FUNCTIONS --------------------

# breakOn :: String -> String -> (String, String)
def breakOn(needle):
    '''A tuple of:
       1. the prefix of haystack before needle,
       2. the remainder of haystack, starting
          with needle.
    '''
    def go(haystack):
        xs = haystack.split(needle)
        return (xs[0], haystack[len(xs[0]):]) if (
            1 < len(xs)
        ) else (haystack, '')
    return lambda haystack: go(haystack) if (
        needle
    ) else None

# enumFromTo :: Int -> Int -> [Int]
def enumFromTo(m):
    '''Enumeration of integer values [m..n]
    '''
    return lambda n: list(range(m, 1 + n))

# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function ->
       fx display function -> f -> xs -> tabular string.
    '''
    def gox(xShow):
        def gofx(fxShow):
            def gof(f):
                def goxs(xs):
                    ys = [xShow(x) for x in xs]
                    w = max(map(len, ys))

                    def arrowed(x, y):
                        return y.rjust(w, ' ') + ' -> ' + (
                            fxShow(f(x))
                        )
                    return s + '\n' + '\n'.join(
                        map(arrowed, xs, ys)
                    )
                return goxs
            return gof
        return gofx
    return gox

# showList :: [a] -> String
def showList(xs):
    '''Stringification of a list.
    '''
    return '[' + ','.join(str(x) for x in xs) + ']'

# MAIN ---
if __name__ == '__main__':
    main()


Range extraction

{{:Range extraction/Format}}

;Task:
* Create a function that takes a list of integers in increasing order and returns a correctly formatted string in the range format.
* Use the function to compute and print the range formatted version of the following ordered list of integers. (The correct answer is: 0-2,4,6-8,11,12,14-25,27-33,35-39).

     0,  1,  2,  4,  6,  7,  8, 11, 12, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
    25, 27, 28, 29, 30, 31, 32, 33, 35, 36,
    37, 38, 39
* Show the output of your program.

;Related task:
*   [[Range expansion]]

Solution:
def range_extract(lst):
    'Yield 2-tuple ranges or 1-tuple single elements from list of increasing ints'
    lenlst = len(lst)
    i = 0
    while i< lenlst:
        low = lst[i]
        while i <lenlst-1 and lst[i]+1 == lst[i+1]: i +=1
        hi = lst[i]
        if   hi - low >= 2:
            yield (low, hi)
        elif hi - low == 1:
            yield (low,)
            yield (hi,)
        else:
            yield (low,)
        i += 1

def printr(ranges):
    print( ','.join( (('%i-%i' % r) if len(r) == 2 else '%i' % r)
                     for r in ranges ) )

if __name__ == '__main__':
    for lst in [[-8, -7, -6, -3, -2, -1, 0, 1, 3, 4, 5, 7,
                 8, 9, 10, 11, 14, 15, 17, 18, 19, 20],
                [0, 1, 2, 4, 6, 7, 8, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22,
                 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39]]:
        #print(list(range_extract(lst)))
        printr(range_extract(lst))


Range extraction

Solution:
'''Range extraction'''

from functools import reduce

# rangeFormat :: [Int] -> String
def rangeFormat(xs):
    '''Range-formatted display string for
       a list of integers.
    '''
    return ','.join([
        rangeString(x) for x
        in splitBy(lambda a, b: 1 < b - a)(xs)
    ])

# rangeString :: [Int] -> String
def rangeString(xs):
    '''Start and end of xs delimited by hyphens
       if there are more than two integers.
       Otherwise, comma-delimited xs.
    '''
    ys = [str(x) for x in xs]
    return '-'.join([ys[0], ys[-1]]) if 2 < len(ys) else (
        ','.join(ys)
    )

# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Test'''

    xs = [
        0, 1, 2, 4, 6, 7, 8, 11, 12, 14,
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
        25, 27, 28, 29, 30, 31, 32, 33, 35, 36,
        37, 38, 39
    ]
    print(
        __doc__ + ':\n[' + '\n'.join(map(
            lambda x: ' ' + repr(x)[1:-1],
            chunksOf(11)(xs)
        )) + " ]\n\n        -> '" + rangeFormat(xs) + "'\n"
    )

# 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 []

# splitBy :: (a -> a -> Bool) -> [a] -> [[a]]
def splitBy(p):
    '''A list split wherever two consecutive
       items match the binary predicate p.
    '''
    # step :: ([[a]], [a], a) -> a -> ([[a]], [a], a)
    def step(acp, x):
        acc, active, prev = acp
        return (acc + [active], [x], x) if p(prev, x) else (
            (acc, active + [x], x)
        )

    # go :: [a] -> [[a]]
    def go(xs):
        if 2 > len(xs):
            return xs
        else:
            h = xs[0]
            ys = reduce(step, xs[1:], ([], [h], h))
            # The accumulated sublists, and the current group.
            return ys[0] + [ys[1]]

    return lambda xs: go(xs)

# MAIN ---
if __name__ == '__main__':
    main()


Rate counter

Counting the frequency at which something occurs is a common activity in measuring performance and managing resources. In this task, we assume that there is some job which we want to perform repeatedly, and we want to know how quickly these jobs are being performed.
Of interest is the code that performs the actual measurements. Any other code (such as job implementation or dispatching) that is required to demonstrate the rate tracking is helpful, but not the focus.

Multiple approaches are allowed (even preferable), so long as they can accomplish these goals:

* Run N seconds worth of jobs and/or Y jobs.
* Report at least three distinct times.

Be aware of the precision and accuracy limitations of your timing mechanisms, and document them if you can.

'''See also:''' [[System time]], [[Time a function]]

Solution:
import subprocess
import time

class Tlogger(object):
    def __init__(self):
        self.counts = 0
        self.tottime = 0.0
        self.laststart = 0.0
        self.lastreport = time.time()

    def logstart(self):
        self.laststart = time.time()

    def logend(self):
        self.counts +=1
        self.tottime += (time.time()-self.laststart)
        if (time.time()-self.lastreport)>5.0:   # report once every 5 seconds
           self.report()

    def report(self):
        if ( self.counts > 4*self.tottime):
            print "Subtask execution rate: %f times/second"% (self.counts/self.tottime);
        else:
            print "Average execution time: %f seconds"%(self.tottime/self.counts);
        self.lastreport = time.time()

def taskTimer( n, subproc_args ):
    logger = Tlogger()

    for x in range(n):
        logger.logstart()
        p = subprocess.Popen(subproc_args)
        p.wait()
        logger.logend()
    logger.report()

import timeit
import sys

def main( ):

    # for accurate timing of code segments
    s = """j = [4*n for n in range(50)]"""
    timer = timeit.Timer(s)
    rzlts = timer.repeat(5, 5000)
    for t in rzlts:
        print "Time for 5000 executions of statement = ",t

    # subprocess execution timing
    print "#times:",sys.argv[1]
    print "Command:",sys.argv[2:]
    print ""
    for k in range(3):
       taskTimer( int(sys.argv[1]), sys.argv[2:])

main()


Read a specific line from a file

Some languages have special semantics for obtaining a known line number from a file.

;Task:
Demonstrate how to obtain the contents of a specific line within a file.

For the purpose of this task demonstrate how the contents of the seventh line of a file can be obtained,   and store it in a variable or in memory   (for potential future use within the program if the code were to become embedded).

If the file does not contain seven lines,   or the seventh line is empty,   or too big to be retrieved,   output an appropriate message.

If no special semantics are available for obtaining the required line,   it is permissible to read line by line.

Note that empty lines are considered and should still be counted.

Also note that for functional languages or languages without variables or storage,   it is permissible to output the extracted data to standard output.

Solution:
from itertools import islice

with open('xxx.txt') as f:
    try:
        line = next(islice(f, 6, 7))
    except StopIteration:
        print('Not 7 lines in file')


Recaman's sequence

The '''Recaman's sequence''' generates Natural numbers.

Starting from a(0)=0, the n'th term a(n), where n>0, is the previous term minus n i.e a(n) = a(n-1) - n but only if this is '''both''' positive ''and'' has not been previousely generated.

If the conditions ''don't'' hold then a(n) = a(n-1) + n.

;Task:
# Generate and show here the first 15 members of the sequence.
# Find and show here, the first duplicated number in the sequence.
# '''Optionally''': Find and show here, how many terms of the sequence are needed until all the integers 0..1000, inclusive, are generated.

;References:
* A005132,  The On-Line Encyclopedia of Integer Sequences.
* The Slightly Spooky Recaman Sequence, Numberphile video.
* Recaman's sequence, on Wikipedia.

Solution:
from itertools import islice

class Recamans():
    "Recamán's sequence generator callable class"
    def __init__(self):
        self.a = None   # Set of results so far
        self.n = None   # n'th term (counting from zero)

    def __call__(self):
        "Recamán's sequence  generator"
        nxt = 0
        a, n = {nxt}, 0
        self.a = a
        self.n = n
        yield nxt
        while True:
            an1, n = nxt, n + 1
            nxt = an1 - n
            if nxt < 0 or nxt in a:
                nxt = an1 + n
            a.add(nxt)
            self.n = n
            yield nxt

if __name__ == '__main__':
    recamans = Recamans()
    print("First fifteen members of Recamans sequence:",
          list(islice(recamans(), 15)))

    so_far = set()
    for term in recamans():
        if term in so_far:
            print(f"First duplicate number in series is: a({recamans.n}) = {term}")
            break
        so_far.add(term)

    n = 1_000
    setn = set(range(n + 1))    # The target set of numbers to be covered
    for _ in recamans():
        if setn.issubset(recamans.a):
            print(f"Range 0 ..{n} is covered by terms up to a({recamans.n})")
            break


Remove lines from a file

Remove a specific line or a number of lines from a file.

This should be implemented as a routine that takes three parameters (filename, starting line, and the number of lines to be removed).

For the purpose of this task, line numbers and the number of lines start at one, so to remove the first two lines from the file foobar.txt, the parameters should be: foobar.txt, 1, 2

Empty lines are considered and should still be counted, and if the specified line is empty, it should still be removed.

An appropriate message should appear if an attempt is made to remove lines beyond the end of the file.

Solution:
#!/usr/bin/env python

import fileinput, sys

fname, start, count = sys.argv[1:4]
start, count = int(start), int(count)

for line in fileinput.input(fname, inplace=1, backup='.orig'):
    if start <= fileinput.lineno() < start + count:
        pass
    else:
        print line.rstrip("\n")
fileinput.close()


Rep-string

Given a series of ones and zeroes in a string, define a repeated string or ''rep-string'' as a string which is created by repeating a substring of the ''first'' N characters of the string ''truncated on the right to the length of the input string, and in which the substring appears repeated at least twice in the original''.

For example, the string '''10011001100''' is a rep-string as the leftmost four characters of '''1001''' are repeated three times and truncated on the right to give the original string.

Note that the requirement for having the repeat occur two or more times means that the repeating unit is ''never'' longer than half the length of the input string.

;Task:
* Write a function/subroutine/method/... that takes a string and returns an indication of if it is a rep-string and the repeated string.   (Either the string that is repeated, or the number of repeated characters would suffice).
* There may be multiple sub-strings that make a string a rep-string - in that case an indication of all, or the longest, or the shortest would suffice.
* Use the function to indicate the repeating substring if any, in the following:

1001110011
1110111011
0010010010
1010101010
1111111111
0100101101
0100100
101
11
00
1

* Show your output on this page.

Solution:
def is_repeated(text):
    'check if the first part of the string is repeated throughout the string'
    for x in range(len(text)//2, 0, -1):
        if text.startswith(text[x:]): return x
    return 0

matchstr = """\
1001110011
1110111011
0010010010
1010101010
1111111111
0100101101
0100100
101
11
00
1
"""
for line in matchstr.split():
    ln = is_repeated(line)
    print('%r has a repetition length of %i i.e. %s'
           % (line, ln, repr(line[:ln]) if ln else '*not* a rep-string'))


Rep-string

Solution:
'''Rep-strings'''

from itertools import (accumulate, chain, cycle, islice)

# repCycles :: String -> [String]
def repCycles(s):
    '''Repeated sequences of characters in s.'''
    n = len(s)
    cs = list(s)

    return [
        x for x in
        tail(inits(take(n // 2)(s)))
        if cs == take(n)(cycle(x))
    ]

# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Tests - longest cycle (if any) in each string.'''
    print(
        fTable('Longest cycles:\n')(repr)(
            lambda xs: ''.join(xs[-1]) if xs else '(none)'
        )(repCycles)([
            '1001110011',
            '1110111011',
            '0010010010',
            '1010101010',
            '1111111111',
            '0100101101',
            '0100100',
            '101',
            '11',
            '00',
            '1',
        ])
    )

# GENERIC -------------------------------------------------

# inits :: [a] -> [[a]]
def inits(xs):
    '''all initial segments of xs, shortest first.'''
    return accumulate(chain([[]], xs), lambda a, x: a + [x])

# tail :: [a] -> [a]
# tail :: Gen [a] -> [a]
def tail(xs):
    '''The elements following the head of a
       (non-empty) list or generator stream.'''
    if isinstance(xs, list):
        return xs[1:]
    else:
        list(islice(xs, 1))  # First item dropped.
        return xs

# 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.'''
    return lambda xs: (
        xs[0:n]
        if isinstance(xs, (list, tuple))
        else list(islice(xs, n))
    )

# OUTPUT FORMATTING ---------------------------------------

# fTable :: String -> (a -> String) ->
#                     (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function ->
                 fx display function ->
          f -> value list -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )

# MAIN ---
if __name__ == '__main__':
    main()


Repeat

Write a procedure which accepts as arguments another procedure and a positive integer.

The latter procedure is executed a number of times equal to the accepted integer.

Solution:
#!/usr/bin/python
def repeat(f,n):
  for i in range(n):
    f();

def procedure():
  print("Example");

repeat(procedure,3); #prints "Example" (without quotes) three times, separated by newlines.


Repeat

Solution:
'''Application of a given function, repeated N times'''

from itertools import repeat
from functools import reduce
from inspect import getsource

# applyN :: Int -> (a -> a) -> a -> a
def applyN(n):
    '''n compounding applications of the supplied
       function f. Equivalent to Church numeral n.
    '''
    def go(f):
        return lambda x: reduce(
            lambda a, g: g(a), repeat(f, n), x
        )
    return lambda f: go(f)

# MAIN ----------------------------------------------------
def main():
    '''Tests - compounding repetition
       of function application.
    '''
    def f(x):
        return x + 'Example\n'

    def g(x):
        return 2 * x

    def h(x):
        return 1.05 * x

    print(
        fTable(__doc__ + ':')(
            lambda fx: '\nRepeated * 3:\n (' + (
                getsource(fst(fx)).strip() + ')(' +
                repr(snd(fx)) + ')'
            )
        )(str)(
            liftA2(applyN(3))(fst)(snd)
        )([(f, '\n'), (g, 1), (h, 100)])
    )

# GENERIC -------------------------------------------------

# 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]

# liftA2 :: (a0 -> b -> c) -> (a -> a0) -> (a -> b) -> a -> c
def liftA2(op):
    '''Lift a binary function to a composition
       over two other functions.
       liftA2 (*) (+ 2) (+ 3) 7 == 90
    '''
    def go(f, g):
        return lambda x: op(
            f(x)
        )(g(x))
    return lambda f: lambda g: go(f, g)

# snd :: (a, b) -> b
def snd(tpl):
    '''Second member of a pair.'''
    return tpl[1]

# fTable :: String -> (a -> String) ->
#                     (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function -> fx display function ->
                     f -> xs -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )

# MAIN ---
if __name__ == '__main__':
    main()


Repunit primes

portmanteau of the words "repetition" and "unit", with unit being "unit value"... or in laymans terms, '''1'''.  So 1, 11, 111, 1111 & 11111 are all repunits.

Every standard integer base has repunits since every base has the digit 1. This task involves finding the repunits in different bases that are prime.

In base two, the repunits 11, 111, 11111, 1111111, etc. are prime. (These correspond to the Mersenne primes.)

In base three: 111, 1111111, 1111111111111, etc.

''Repunit primes, by definition, are also [[circular primes]].''

Any repunit in any base having a composite number of digits is necessarily composite. Only repunits (in any base) having a prime number of digits ''might'' be prime.

Rather than expanding the repunit out as a giant list of '''1'''s or converting to base 10, it is common to just list the ''number'' of '''1'''s in the repunit; effectively the digit count. The base two repunit primes listed above would be represented as: 2, 3, 5, 7, etc.

Many of these sequences exist on OEIS, though they aren't specifically listed as "repunit prime digits" sequences.

Some bases have very few repunit primes. Bases 4, 8, and likely 16 have only one. Base 9 has none at all. Bases above 16 may have repunit primes as well... but this task is getting large enough already.

;Task

* For bases 2 through 16, Find and show, here on this page, the repunit primes as digit counts, up to a limit of 1000.

;Stretch

* Increase the limit to 2700 (or as high as you have patience for.)

;See also

;* Wikipedia: Repunit primes
;* OEIS:A000043 - Mersenne exponents: primes p such that 2^p - 1 is prime. Then 2^p - 1 is called a Mersenne prime (base 2)
;* OEIS:A028491 - Numbers k such that (3^k - 1)/2 is prime (base 3)
;* OEIS:A004061 - Numbers n such that (5^n - 1)/4 is prime (base 5)
;* OEIS:A004062 - Numbers n such that (6^n - 1)/5 is prime (base 6)
;* OEIS:A004063 - Numbers k such that (7^k - 1)/6 is prime (base 7)
;* OEIS:A004023 - Indices of prime repunits: numbers n such that 11...111 (with n 1's) = (10^n - 1)/9 is prime (base 10)
;* OEIS:A005808 - Numbers k such that (11^k - 1)/10 is prime (base 11)
;* OEIS:A004064 - Numbers n such that (12^n - 1)/11 is prime (base 12)
;* OEIS:A016054 - Numbers n such that (13^n - 1)/12 is prime (base 13)
;* OEIS:A006032 - Numbers k such that (14^k - 1)/13 is prime (base 14)
;* OEIS:A006033 - Numbers n such that (15^n - 1)/14 is prime (base 15)
;* Related task: Circular primes

Solution:
from sympy import isprime
for b in range(2, 17):
    print(b, [n for n in range(2, 1001) if isprime(n) and isprime(int('1'*n, base=b))])


Resistor mesh

Given    10x10    grid nodes   (as shown in the image)   interconnected by    1O    resistors as shown,
find the resistance between points   '''A'''   and   '''B'''.

;See also:
*   (humor, nerd sniping)   xkcd.com cartoon (you can solve that for extra credits)
*   An article on how to calculate this and an implementation in Mathematica

Solution:
DIFF_THRESHOLD = 1e-40

class Fixed:
    FREE = 0
    A = 1
    B = 2

class Node:
    __slots__ = ["voltage", "fixed"]
    def __init__(self, v=0.0, f=Fixed.FREE):
        self.voltage = v
        self.fixed = f

def set_boundary(m):
    m[1][1] = Node( 1.0, Fixed.A)
    m[6][7] = Node(-1.0, Fixed.B)

def calc_difference(m, d):
    h = len(m)
    w = len(m[0])
    total = 0.0

    for i in xrange(h):
        for j in xrange(w):
            v = 0.0
            n = 0
            if i != 0:  v += m[i-1][j].voltage; n += 1
            if j != 0:  v += m[i][j-1].voltage; n += 1
            if i < h-1: v += m[i+1][j].voltage; n += 1
            if j < w-1: v += m[i][j+1].voltage; n += 1
            v = m[i][j].voltage - v / n

            d[i][j].voltage = v
            if m[i][j].fixed == Fixed.FREE:
                total += v ** 2
    return total

def iter(m):
    h = len(m)
    w = len(m[0])
    difference = [[Node() for j in xrange(w)] for i in xrange(h)]

    while True:
        set_boundary(m) # Enforce boundary conditions.
        if calc_difference(m, difference) < DIFF_THRESHOLD:
            break
        for i, di in enumerate(difference):
            for j, dij in enumerate(di):
                m[i][j].voltage -= dij.voltage

    cur = [0.0] * 3
    for i, di in enumerate(difference):
        for j, dij in enumerate(di):
            cur[m[i][j].fixed] += (dij.voltage *
                (bool(i) + bool(j) + (i < h-1) + (j < w-1)))

    return (cur[Fixed.A] - cur[Fixed.B]) / 2.0

def main():
    w = h = 10
    mesh = [[Node() for j in xrange(w)] for i in xrange(h)]
    print "R = %.16f" % (2 / iter(mesh))

main()


Resistor mesh

Solution:
import sys, copy
from fractions import Fraction

def gauss(a, b):
    n, p = len(a), len(a[0])
    for i in range(n):
        t = abs(a[i][i])
        k = i
        for j in range(i + 1, n):
            if abs(a[j][i]) > t:
                t = abs(a[j][i])
                k = j
        if k != i:
            for j in range(i, n):
                a[i][j], a[k][j] = a[k][j], a[i][j]
            b[i], b[k] = b[k], b[i]
        t = 1/a[i][i]
        for j in range(i + 1, n):
            a[i][j] *= t
        b[i] *= t
        for j in range(i + 1, n):
            t = a[j][i]
            for k in range(i + 1, n):
                a[j][k] -= t*a[i][k]
            b[j] -= t * b[i]
    for i in range(n - 1, -1, -1):
        for j in range(i):
            b[j] -= a[j][i]*b[i]
    return b

def resistor_grid(p, q, ai, aj, bi, bj):
    n = p*q
    I = Fraction(1, 1)
    v = [0*I]*n
    a = [copy.copy(v) for i in range(n)]
    for i in range(p):
        for j in range(q):
            k = i*q + j
            if i == ai and j == aj:
                a[k][k] = I
            else:
                c = 0
                if i + 1 < p:
                    c += 1
                    a[k][k + q] = -1
                if i >= 1:
                    c += 1
                    a[k][k - q] = -1
                if j + 1 < q:
                    c += 1
                    a[k][k + 1] = -1
                if j >= 1:
                    c += 1
                    a[k][k - 1] = -1
                a[k][k] = c*I
    b = [0*I]*n
    k = bi*q + bj
    b[k] = 1
    return gauss(a, b)[k]

def main(arg):
    r = resistor_grid(int(arg[0]), int(arg[1]), int(arg[2]), int(arg[3]), int(arg[4]), int(arg[5]))
    print(r)
    print(float(r))

main(sys.argv[1:])

# Output:
# python grid.py 10 10 1 1 7 6
# 455859137025721/283319837425200
# 1.6089912417307297


Reverse words in a string

Reverse the order of all tokens in each of a number of strings and display the result;   the order of characters within a token should not be modified.

;Example:
Hey you, Bub!    would be shown reversed as:    Bub! you, Hey

Tokens are any non-space characters separated by spaces (formally, white-space);   the visible punctuation form part of the word within which it is located and should not be modified.

You may assume that there are no significant non-visible characters in the input.   Multiple or superfluous spaces may be compressed into a single space.

Some strings have no tokens, so an empty string   (or one just containing spaces)   would be the result.

'''Display''' the strings in order   (1st, 2nd, 3rd, ***),   and one string per line.

(You can consider the ten strings as ten lines, and the tokens as words.)

;Input data

             (ten lines within the box)
 line
     +----------------------------------------+
   1 |  ---------- Ice and Fire ------------  |
   2 |                                        |  <--- a blank line here.
   3 |  fire, in end will world the say Some  |
   4 |  ice. in say Some                      |
   5 |  desire of tasted I've what From       |
   6 |  fire. favor who those with hold I     |
   7 |                                        |  <--- a blank line here.
   8 |  ... elided paragraph last ...         |
   9 |                                        |  <--- a blank line here.
  10 |  Frost Robert -----------------------  |
     +----------------------------------------+

;Cf.
* [[Phrase reversals]]

Solution:
text = '''\
---------- Ice and Fire ------------

fire, in end will world the say Some
ice. in say Some
desire of tasted I've what From
fire. favor who those with hold I

... elided paragraph last ...

Frost Robert -----------------------'''

for line in text.split('\n'): print(' '.join(line.split()[::-1]))


Roman numerals/Decode

Create a function that takes a Roman numeral as its argument and returns its value as a numeric decimal integer.

You don't need to validate the form of the Roman numeral.

Modern Roman numerals are written by expressing each decimal digit of the number to be encoded separately,
starting with the leftmost decimal digit and skipping any '''0'''s   (zeroes).

'''1990''' is rendered as   '''MCMXC'''     (1000 = M,   900 = CM,   90 = XC)     and
'''2008''' is rendered as   '''MMVIII'''       (2000 = MM,   8 = VIII).

The Roman numeral for '''1666''',   '''MDCLXVI''',   uses each letter in descending order.

Solution:
_rdecode = dict(zip('MDCLXVI', (1000, 500, 100, 50, 10, 5, 1)))

def decode( roman ):
    result = 0
    for r, r1 in zip(roman, roman[1:]):
        rd, rd1 = _rdecode[r], _rdecode[r1]
        result += -rd if rd < rd1 else rd
    return result + _rdecode[roman[-1]]

if __name__ == '__main__':
    for r in 'MCMXC MMVIII MDCLXVI'.split():
        print( r, decode(r) )


Roman numerals/Decode

Solution:
'''Roman numerals decoded'''

from operator import mul
from functools import reduce
from collections import defaultdict
from itertools import accumulate, chain, cycle

# intFromRoman :: String -> Maybe Int
def intFromRoman(s):
    '''Just the integer represented by a Roman
       numeral string, or Nothing if any
       characters are unrecognised.
    '''
    dct = defaultdict(
        lambda: None,
        zip(
            'IVXLCDM',
            accumulate(chain([1], cycle([5, 2])), mul)
        )
    )

    def go(mb, x):
        '''Just a letter value added to or
           subtracted from a total, or Nothing
           if no letter value is defined.
        '''
        if None in (mb, x):
            return None
        else:
            r, total = mb
            return x, total + (-x if x < r else x)

    return bindMay(reduce(
        go,
        [dct[k.upper()] for k in reversed(list(s))],
        (0, 0)
    ))(snd)

# ------------------------- TEST -------------------------
def main():
    '''Testing a sample of dates.'''

    print(
        fTable(__doc__ + ':\n')(str)(
            maybe('(Contains unknown character)')(str)
        )(
            intFromRoman
        )([
            "MDCLXVI", "MCMXC", "MMVIII",
            "MMXVI", "MMXVIII", "MMZZIII"
        ])
    )

# ----------------------- GENERIC ------------------------

# bindMay (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
def bindMay(m):
    '''Injection operator for the Maybe monad.
       If m is Nothing, it is passed straight through.
       If m is Just(x), the result is an application
       of the (a -> Maybe b) function (mf) to x.'''
    return lambda mf: (
        m if None is m else mf(m)
    )

# maybe :: b -> (a -> b) -> Maybe a -> b
def maybe(v):
    '''Either the default value v, if m is Nothing,
       or the application of f to x,
       where m is Just(x).
    '''
    return lambda f: lambda m: v if None is m else (
        f(m)
    )

# snd :: (a, b) -> b
def snd(ab):
    '''Second member of a pair.'''
    return ab[1]

# ---------------------- FORMATTING ----------------------

# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function ->
       fx display function -> f -> xs -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: (
                f'{y.rjust(w, " ")} -> {fxShow(f(x))}'
            ),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: (
        lambda xs: go(xShow, fxShow, f, xs)
    )

# MAIN ---
if __name__ == '__main__':
    main()


Roman numerals/Encode

Create a function taking a positive integer as its parameter and returning a string containing the Roman numeral representation of that integer. Modern Roman numerals are written by expressing each digit separately, starting with the left most digit and skipping any digit with a value of zero.

In Roman numerals:
* 1990  is rendered: 1000=M, 900=CM, 90=XC; resulting in MCMXC
* 2008  is written as 2000=MM, 8=VIII; or MMVIII
* 1666  uses each Roman symbol in descending order: MDCLXVI

Solution:
def toRoman(n):
    res=''		#converts int to str(Roman numeral)
    reg=n		#using the numerals (M,D,C,L,X,V,I)
    if reg<4000:#no more than three repetitions
        while reg>=1000:	#thousands up to MMM
            res+='M'		#MAX is MMMCMXCIX
            reg-=1000
        if reg>=900:		#nine hundreds in 900-999
            res+='CM'
            reg-=900
        if reg>=500:		#five hudreds in 500-899
            res+='D'
            reg-=500
        if reg>=400:		#four hundreds in 400-499
            res+='CD'
            reg-=400
        while reg>=100:		#hundreds in 100-399
            res+='C'
            reg-=100
        if reg>=90:			#nine tens in 90-99
            res+='XC'
            reg-=90
        if reg>=50:			#five Tens in 50-89
            res+='L'
            reg-=50
        if reg>=40:
            res+='XL'		#four Tens
            reg-=40
        while reg>=10:
            res+="X"		#tens
            reg-=10
        if reg>=9:
            res+='IX'		#nine Units
            reg-=9
        if reg>=5:
            res+='V'		#five Units
            reg-=5
        if reg>=4:
            res+='IV'		#four Units
            reg-=4
        while reg>0:		#three or less Units
            res+='I'
            reg-=1
    return res


Roman numerals/Encode

Solution:
'''Encoding Roman Numerals'''

from functools import reduce
from itertools import chain

# romanFromInt ::  Int -> String
def romanFromInt(n):
    '''A string of Roman numerals encoding an integer.'''
    def go(a, ms):
        m, s = ms
        q, r = divmod(a, m)
        return (r, s * q)

    return concat(snd(mapAccumL(go)(n)(
        zip([
            1000, 900, 500, 400, 100, 90, 50,
            40, 10, 9, 5, 4, 1
        ], [
            'M', 'CM', 'D', 'CD', 'C', 'XC', 'L',
            'XL', 'X', 'IX', 'V', 'IV', 'I'
        ])
    )))

# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''Sample of years'''
    for s in [
            romanFromInt(x) for x in [
                1666, 1990, 2008, 2016, 2018, 2020
            ]
    ]:
        print(s)

# ------------------ GENERIC FUNCTIONS -------------------

# concat :: [[a]] -> [a]
# concat :: [String] -> String
def concat(xxs):
    '''The concatenation of all the elements in a list.'''
    xs = list(chain.from_iterable(xxs))
    unit = '' if isinstance(xs, str) else []
    return unit if not xs else (
        ''.join(xs) if isinstance(xs[0], str) else xs
    )

# 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, []))
    )

# snd :: (a, b) -> b
def snd(tpl):
    '''Second component of a tuple.'''
    return tpl[1]

# MAIN ---
if __name__ == '__main__':
    main()


Runge-Kutta method

Given the example Differential equation:
:y'(t) = t \times \sqrt {y(t)}
With initial condition:
:t_0 = 0 and y_0 = y(t_0) = y(0) = 1
This equation has an exact solution:
:y(t) = \tfrac{1}{16}(t^2 +4)^2

;Task
Demonstrate the commonly used explicit   fourth-order Runge-Kutta method   to solve the above differential equation.
* Solve the given differential equation over the range t = 0 \ldots 10 with a step value of \delta t=0.1 (101 total points, the first being given)
* Print the calculated values of y at whole numbered t's (0.0, 1.0, \ldots 10.0) along with error as compared to the exact solution.

;Method summary
Starting with a given y_n and t_n calculate:
:\delta y_1 = \delta t\times y'(t_n, y_n)\quad
:\delta y_2 = \delta t\times y'(t_n + \tfrac{1}{2}\delta t , y_n + \tfrac{1}{2}\delta y_1)
:\delta y_3 = \delta t\times y'(t_n + \tfrac{1}{2}\delta t , y_n + \tfrac{1}{2}\delta y_2)
:\delta y_4 = \delta t\times y'(t_n + \delta t , y_n + \delta y_3)\quad
then:
:y_{n+1} = y_n + \tfrac{1}{6} (\delta y_1 + 2\delta y_2 + 2\delta y_3 + \delta y_4)
:t_{n+1} = t_n + \delta t\quad

Solution:
from math import sqrt

def rk4(f, x0, y0, x1, n):
    vx = [0] * (n + 1)
    vy = [0] * (n + 1)
    h = (x1 - x0) / float(n)
    vx[0] = x = x0
    vy[0] = y = y0
    for i in range(1, n + 1):
        k1 = h * f(x, y)
        k2 = h * f(x + 0.5 * h, y + 0.5 * k1)
        k3 = h * f(x + 0.5 * h, y + 0.5 * k2)
        k4 = h * f(x + h, y + k3)
        vx[i] = x = x0 + i * h
        vy[i] = y = y + (k1 + k2 + k2 + k3 + k3 + k4) / 6
    return vx, vy

def f(x, y):
    return x * sqrt(y)

vx, vy = rk4(f, 0, 1, 10, 100)
for x, y in list(zip(vx, vy))[::10]:
    print("%4.1f %10.5f %+12.4e" % (x, y, y - (4 + x * x)**2 / 16))

 0.0    1.00000  +0.0000e+00
 1.0    1.56250  -1.4572e-07
 2.0    4.00000  -9.1948e-07
 3.0   10.56250  -2.9096e-06
 4.0   24.99999  -6.2349e-06
 5.0   52.56249  -1.0820e-05
 6.0   99.99998  -1.6595e-05
 7.0  175.56248  -2.3518e-05
 8.0  288.99997  -3.1565e-05
 9.0  451.56246  -4.0723e-05
10.0  675.99995  -5.0983e-05


Runtime evaluation/In an environment

Given a program in the language (as a string or AST) with a free variable named x (or another name if that is not valid syntax), evaluate it with x bound to a provided value, then evaluate it again with x bound to another provided value, then subtract the result of the first from the second and return or print it.

Do so in a way which:
* does not involve string manipulation of the input source code
* is plausibly extensible to a runtime-chosen set of bindings rather than just x
* does not make x a ''global'' variable

or note that these are impossible.

;See also:
* For more general examples and language-specific details, see [[Eval]].
* [[Dynamic variable names]] is a similar task.

Solution:
>>> def eval_with_args(code, **kwordargs):
	return eval(code, kwordargs)

>>> code = '2 ** x'
>>> eval_with_args(code, x=5) - eval_with_args(code, x=3)
24
>>> code = '3 * x + y'
>>> eval_with_args(code, x=5, y=2) - eval_with_args(code, x=3, y=1)
7


SHA-1

'''SHA-1''' or '''SHA1''' is a one-way hash function;
it computes a 160-bit message digest.
SHA-1 often appears in security protocols; for example,
many HTTPS websites use RSA with SHA-1 to secure their connections.
BitTorrent uses SHA-1 to verify downloads.
Git and Mercurial use SHA-1 digests to identify commits.

A US government standard, FIPS 180-1, defines SHA-1.

Find the SHA-1 message digest for a string of [[octet]]s. You may either call a SHA-1 library, or implement SHA-1 in your language. Both approaches interest Rosetta Code.

{{alertbox|lightgray|'''Warning:''' SHA-1 has known weaknesses. Theoretical attacks may find a collision after 252 operations, or perhaps fewer.
This is much faster than a brute force attack of 280 operations. USgovernment deprecated SHA-1.
For production-grade cryptography, users may consider a stronger alternative, such as SHA-256 (from the SHA-2 family) or the upcoming SHA-3.}}

Solution:
import hashlib
h = hashlib.sha1()
h.update(bytes("Ars longa, vita brevis", encoding="ASCII"))
h.hexdigest()
# "e640d285242886eb96ab80cbf858389b3df52f43"


Sailors, coconuts and a monkey problem

Five sailors are shipwrecked on an island and collect a large pile of coconuts during the day.

That night the first sailor wakes up and decides to take his first share early  so tries to divide the pile of coconuts equally into five piles but finds that there is one coconut left over, so he tosses it to a monkey and then hides "his" one of the five equally sized piles of coconuts and pushes the other four piles together to form a single visible pile of coconuts again and goes to bed.

To cut a long story short, each of the sailors in turn gets up once during the night and performs the same actions of dividing the coconut pile into five, finding that one coconut is left over and giving that single remainder coconut to the monkey.

In the morning (after the surreptitious and separate action of each of the five sailors during the night), the remaining coconuts are divided into five equal piles for each of the sailors, whereupon it is found that the pile of coconuts divides equally amongst the sailors with no remainder. (Nothing for the monkey in the morning.)

;The task:
# Calculate the minimum possible size of the initial pile of coconuts collected during the first day.
# Use a method that assumes an answer is possible, and then applies the constraints of the tale to see if it is correct. (I.e. no applying some formula that generates the correct answer without integer divisions and remainders and tests on remainders; but constraint solvers ''are'' allowed.)
# Calculate the size of the initial pile of coconuts if six sailors were marooned and went through a similar process (but split into six piles instead of five of course).
# Show your answers here.

;Extra credit (optional):
* Give some indication of the number of coconuts each sailor hides during the night.

;Note:
* Of course the tale is told in a world where the collection of any amount of coconuts in a day and multiple divisions of the pile, etc can occur in time fitting the story line, so as not to affect the mathematics.
* The tale is also told in a version where the monkey also gets a coconut in the morning. This is ''not'' that tale!

;C.f:
* Monkeys and Coconuts - Numberphile (Video) Analytical solution.
* A002021: Pile of coconuts problem The On-Line Encyclopedia of Integer Sequences. (Although some of its references may use the alternate form of the tale).

Solution:
def monkey_coconuts(sailors=5):
    "Parameterised the number of sailors using an inner loop including the last mornings case"
    nuts = sailors
    while True:
        n0, wakes = nuts, []
        for sailor in range(sailors + 1):
            portion, remainder = divmod(n0, sailors)
            wakes.append((n0, portion, remainder))
            if portion <= 0 or remainder != (1 if sailor != sailors else 0):
                nuts += 1
                break
            n0 = n0 - portion - remainder
        else:
            break
    return nuts, wakes

if __name__ == "__main__":
    for sailors in [5, 6]:
        nuts, wake_stats = monkey_coconuts(sailors)
        print("\nFor %i sailors the initial nut count is %i" % (sailors, nuts))
        print("On each waking, the nut count, portion taken, and monkeys share are:\n ",
              ',\n  '.join(repr(ws) for ws in wake_stats))


Same fringe

Write a routine that will compare the leaves ("fringe") of two binary trees to determine whether they are the same list of leaves when visited left-to-right.  The structure or balance of the trees does not matter; only the number, order, and value of the leaves is important.

Any solution is allowed here, but many computer scientists will consider it inelegant to collect either fringe in its entirety before starting to collect the other one.  In fact, this problem is usually proposed in various forums as a way to show off various forms of concurrency (tree-rotation algorithms have also been used to get around the need to collect one tree first).  Thinking of it a slightly different way, an elegant solution is one that can perform the minimum amount of work to falsify the equivalence of the fringes when they differ somewhere in the middle, short-circuiting the unnecessary additional traversals and comparisons.

Any representation of a binary tree is allowed, as long as the nodes are orderable, and only downward links are used (for example, you may not use parent or sibling pointers to avoid recursion).

Solution:
try:
    from itertools import zip_longest as izip_longest # Python 3.x
except:
    from itertools import izip_longest                # Python 2.6+

def fringe(tree):
    """Yield tree members L-to-R depth first,
    as if stored in a binary tree"""
    for node1 in tree:
        if isinstance(node1, tuple):
            for node2 in fringe(node1):
                yield node2
        else:
            yield node1

def same_fringe(tree1, tree2):
    return all(node1 == node2 for node1, node2 in
               izip_longest(fringe(tree1), fringe(tree2)))

if __name__ == '__main__':
    a = 1, 2, 3, 4, 5, 6, 7, 8
    b = 1, (( 2, 3 ), (4, (5, ((6, 7), 8))))
    c = (((1, 2), 3), 4), 5, 6, 7, 8

    x = 1, 2, 3, 4, 5, 6, 7, 8, 9
    y = 0, 2, 3, 4, 5, 6, 7, 8
    z = 1, 2, (4, 3), 5, 6, 7, 8

    assert same_fringe(a, a)
    assert same_fringe(a, b)
    assert same_fringe(a, c)

    assert not same_fringe(a, x)
    assert not same_fringe(a, y)
    assert not same_fringe(a, z)


Search in paragraph's text

The goal is to verify the presence of a word or regular expression within several paragraphs of text (structured or not) and to format the output of the relevant paragraphs before putting them on the standard output.

So here, let's imagine that we are trying to verify the presence of a keyword "SystemError" within what I want to call "the paragraphs" "Traceback (most recent call last):" in the file Traceback.txt

cat Traceback.txt :

2018-06-19 23:19:34,877 ERROR Processes plugin raised an exception.
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/landscape/sysinfo/sysinfo.py", line 99, in run
    result = plugin.run()
  File "/usr/lib/python3/dist-packages/landscape/sysinfo/processes.py", line 18, in run
    for process_info in info.get_all_process_info():
  File "/usr/lib/python3/dist-packages/landscape/lib/process.py", line 39, in get_all_process_info
    process_info = self.get_process_info(process_id)
  File "/usr/lib/python3/dist-packages/landscape/lib/process.py", line 61, in get_process_info
    cmd_line = file.readline()
  File "/usr/lib/python3.6/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 152: ordinal not in range(128)

2018-06-19 23:19:34,877 ERROR Processes plugin raised an exception.
Traceback (most recent call last):
    vmodl.fault.SystemError: (vmodl.fault.SystemError) {
    dynamicType = ,
    dynamicProperty = (vmodl.DynamicProperty) [],
    msg = 'A general system error occurred: Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.',
    faultCause = ,
    faultMessage = (vmodl.LocalizableMessage) [],
    reason = 'Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.'
    }

[Tue Jan 21 16:16:19.250245 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] Traceback (most recent call last):
[Tue Jan 21 16:16:19.252221 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] SystemError: unable to access /home/dir
[Tue Jan 21 16:16:19.249067 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] mod_wsgi (pid=6515): Failed to exec Python script file '/home/pi/RaspBerryPiAdhan/www/sysinfo.wsgi'.
[Tue Jan 21 16:16:19.249609 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] mod_wsgi (pid=6515): Exception occurred processing WSGI script '/home/pi/RaspBerryPiAdhan/www/sysinfo.wsgi'.

[Tue Jan 21 17:16:19.250245 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] Traceback (most recent call last):
[Tue Jan 21 17:16:19.250679 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757]   File "/home/pi/RaspBerryPiAdhan/www/sysinfo.wsgi", line 5, in
[Tue Jan 21 17:16:19.251735 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757]     from test import app as application
[Tue Jan 21 17:16:19.252221 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] ImportError: cannot import name app

2021-04-23 17:13:14,425 ERROR    Network plugin raised an exception.
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/landscape/sysinfo/sysinfo.py", line 99,
in run
    result = plugin.run()
  File "/usr/lib/python3/dist-packages/landscape/sysinfo/network.py", line 36,
in run
    device_info = self._get_device_info()
  File "/usr/lib/python3/dist-packages/landscape/lib/network.py", line 163, in
get_active_device_info
    speed, duplex = get_network_interface_speed(
  File "/usr/lib/python3/dist-packages/landscape/lib/network.py", line 249, in
get_network_interface_speed
    res = status_cmd.tostring()
AttributeError: 'array.array' object has no attribute 'tostring'

11/01 18:24:57.726 ERROR| log:0072| post-test sysinfo error: 11/01 18:24:57.727 ERROR| traceback:0013| Traceback (most recent call last): 11/01 18:24:57.728 ERROR| traceback:0013| File "/tmp/sysinfo/autoserv-0tMj3m/common_lib/log.py", line 70, in decorated_func 11/01 18:24:57.729 ERROR| traceback:0013| fn(*args, **dargs) 11/01 18:24:57.730 ERROR| traceback:0013| File "/tmp/sysinfo/autoserv-0tMj3m/bin/base_sysinfo.py", line 286, in log_after_each_test 11/01 18:24:57.731 ERROR| traceback:0013| old_packages = set(self._installed_packages) 11/01 18:24:57.731 ERROR| traceback:0013| TypeError: 'NoneType' object is not iterable

12/01 19:24:57.726 ERROR| log:0072| post-test sysinfo error: 11/01 18:24:57.727 ERROR| traceback:0013| Traceback (most recent call last): 11/01 18:24:57.728 ERROR| traceback:0013| File "/tmp/sysinfo/autoserv-0tMj3m/common_lib/log.py", line 70, in decorated_func 11/01 18:24:57.729 ERROR| traceback:0013| fn(*args, **dargs) 11/01 18:24:57.730 ERROR| traceback:0013| File "/tmp/sysinfo/autoserv-0tMj3m/bin/base_sysinfo.py", line 286, in log_after_each_test 11/01 18:24:57.731 ERROR| traceback:0013| old_packages = set(self._installed_packages) 11/01 18:24:57.731 ERROR| traceback:0013| SystemError: no such file or directory

Traceback (most recent call last):
    File "/usr/lib/vmware-vpx/vsan-health/pyMoVsan/VsanClusterPrototypeImpl.py", line 1492, in WaitForUpdateTask
    WaitForTask(task)
    File "/usr/lib/vmware-vpx/pyJack/pyVim/task.py", line 123, in WaitForTask
    raise task.info.error
    vmodl.fault.SystemError: (vmodl.fault.SystemError) {
    dynamicType = ,
    dynamicProperty = (vmodl.DynamicProperty) [],
    msg = 'A general system error occurred: Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.',
    faultCause = ,
    faultMessage = (vmodl.LocalizableMessage) [],
    reason = 'Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.'
    }

The expected result must be formated with ---------------- for paragraph's separator AND "Traceback (most recent call last):" as the beginning of each relevant's paragraph :

Traceback (most recent call last):
    vmodl.fault.SystemError: (vmodl.fault.SystemError) {
    dynamicType = ,
    dynamicProperty = (vmodl.DynamicProperty) [],
    msg = 'A general system error occurred: Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.',
    faultCause = ,
    faultMessage = (vmodl.LocalizableMessage) [],
    reason = 'Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.'
    }
----------------
Traceback (most recent call last):
[Tue Jan 21 16:16:19.252221 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] SystemError: unable to access /home/dir
[Tue Jan 21 16:16:19.249067 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] mod_wsgi (pid=6515): Failed to exec Python script file '/home/pi/RaspBerryPiAdhan/www/sysinfo.wsgi'.
[Tue Jan 21 16:16:19.249609 2020] [wsgi:error] [pid 6515:tid 3041002528] [remote 10.0.0.12:50757] mod_wsgi (pid=6515): Exception occurred processing WSGI script '/home/pi/RaspBerryPiAdhan/www/sysinfo.wsgi'.
----------------
Traceback (most recent call last): 11/01 18:24:57.728 ERROR| traceback:0013| File "/tmp/sysinfo/autoserv-0tMj3m/common_lib/log.py", line 70, in decorated_func 11/01 18:24:57.729 ERROR| traceback:0013| fn(*args, **dargs) 11/01 18:24:57.730 ERROR| traceback:0013| File "/tmp/sysinfo/autoserv-0tMj3m/bin/base_sysinfo.py", line 286, in log_after_each_test 11/01 18:24:57.731 ERROR| traceback:0013| old_packages = set(self._installed_packages) 11/01 18:24:57.731 ERROR| traceback:0013| SystemError: no such file or directory
----------------
Traceback (most recent call last):
    File "/usr/lib/vmware-vpx/vsan-health/pyMoVsan/VsanClusterPrototypeImpl.py", line 1492, in WaitForUpdateTask
    WaitForTask(task)
    File "/usr/lib/vmware-vpx/pyJack/pyVim/task.py", line 123, in WaitForTask
    raise task.info.error
    vmodl.fault.SystemError: (vmodl.fault.SystemError) {
    dynamicType = ,
    dynamicProperty = (vmodl.DynamicProperty) [],
    msg = 'A general system error occurred: Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.',
    faultCause = ,
    faultMessage = (vmodl.LocalizableMessage) [],
    reason = 'Unable to complete Sysinfo operation. Please see the VMkernel log file for more details.: Sysinfo error: Bad parameterSee VMkernel log for details.'
    }
----------------

Solution:
with open('Traceback.txt', 'r' ) as f:
    rawText = f.read()

paragraphs = rawText.split( "\n\n" )

for p in paragraphs:
    if "SystemError" in p:

        index = p.find( "Traceback (most recent call last):" )

        if -1 != index:
            print( p[index:] )
            print( "----------------" )


Selectively replace multiple instances of a character within a string

Task
This is admittedly a trivial task but I thought it would be interesting to see how succinctly (or otherwise) different languages can handle it.

Given the string: "abracadabra", replace programatically:

* the first 'a' with 'A'
* the second 'a' with 'B'
* the fourth 'a' with 'C'
* the fifth 'a' with 'D'
* the first 'b' with 'E'
* the second 'r' with 'F'

Note that there is no replacement for the third 'a', second 'b' or first 'r'.

The answer should, of course, be : "AErBcadCbFD".

Solution:
import functools

from typing import Iterable
from typing import Tuple

@functools.cache
def find_nth(s: str, sub: str, n: int) -> int:
    assert n >= 1
    if n == 1:
        return s.find(sub)
    return s.find(sub, find_nth(s, sub, n - 1) + 1)

def selective_replace(s: str, ops: Iterable[Tuple[int, str, str]]) -> str:
    chars = list(s)
    for n, old, new in ops:
        chars[find_nth(s, old, n)] = new
    return "".join(chars)

print(
    selective_replace(
        "abracadabra",
        [
            (1, "a", "A"),  # the first 'a' with 'A'
            (2, "a", "B"),  # the second 'a' with 'B'
            (4, "a", "C"),  # the fourth 'a' with 'C'
            (5, "a", "D"),  # the fifth 'a' with 'D'
            (1, "b", "E"),  # the first 'b' with 'E'
            (2, "r", "F"),  # the second 'r' with 'F'
        ],
    )
)


Self-describing numbers

{{task}}There are several so-called "self-describing" or "self-descriptive" integers.

An integer is said to be "self-describing" if it has the property that, when digit positions are labeled 0 to N-1, the digit in each position is equal to the number of times that that digit appears in the number.

For example,   '''2020'''   is a four-digit self describing number:

*   position   0   has value   2   and there are two 0s in the number;
*   position   1   has value   0   and there are no 1s in the number;
*   position   2   has value   2   and there are two 2s;
*   position   3   has value   0   and there are zero 3s.

Self-describing numbers < 100.000.000  are:     1210,   2020,   21200,   3211000,   42101000.

;Task Description
# Write a function/routine/method/... that will check whether a given positive integer is self-describing.
# As an optional stretch goal - generate and display the set of self-describing numbers.

;Related tasks:
*   [[Fours is the number of letters in the ...]]
*   [[Look-and-say sequence]]
*   [[Number names]]
*   [[Self-referential sequence]]
*   [[Spelling of ordinal numbers]]

Solution:
>>> def isSelfDescribing(n):
	s = str(n)
	return all(s.count(str(i)) == int(ch) for i, ch in enumerate(s))

>>> [x for x in range(4000000) if isSelfDescribing(x)]
[1210, 2020, 21200, 3211000]
>>> [(x, isSelfDescribing(x)) for x in (1210, 2020, 21200, 3211000, 42101000, 521001000, 6210001000)]
[(1210, True), (2020, True), (21200, True), (3211000, True), (42101000, True), (521001000, True), (6210001000, True)]


Self numbers

A number n is a self number if there is no number g such that g + the sum of g's digits = n. So 18 is not a self number because 9+9=18, 43 is not a self number because 35+5+3=43.

The task is:
  Display the first 50 self numbers;
  I believe that the 100000000th self number is 1022727208. You should either confirm or dispute my conjecture.

224036583-1 is a Mersenne prime, claimed to also be a self number. Extra credit to anyone proving it.

;See also:

;*OEIS: A003052 - Self numbers or Colombian numbers
;*Wikipedia: Self numbers

Solution:
class DigitSumer :
    def __init__(self):
        sumdigit = lambda n : sum( map( int,str( n )))
        self.t = [sumdigit( i ) for i in xrange( 10000 )]
    def __call__ ( self,n ):
        r = 0
        while n >= 10000 :
            n,q = divmod( n,10000 )
            r += self.t[q]
        return r + self.t[n]

def self_numbers ():
    d = DigitSumer()
    s = set([])
    i = 1
    while 1 :
        n = i + d( i )
        if i in s :
            s.discard( i )
        else:
            yield i
        s.add( n )
        i += 1

import time
p = 100
t = time.time()
for i,s in enumerate( self_numbers(),1 ):
    if i <= 50 :
        print s,
        if i == 50 : print
    if i == p :
        print '%7.1f sec  %9dth = %d'%( time.time()-t,i,s )
        p *= 10


Semordnilap

A semordnilap is a word (or phrase) that spells a different word (or phrase) backward. "Semordnilap" is a word that itself is a semordnilap.

Example: ''lager'' and ''regal''

;Task
This task does not consider semordnilap phrases, only single words.
Using only words from this list, report the total number of unique semordnilap pairs, and print 5 examples.
Two matching semordnilaps, such as ''lager'' and ''regal'', should be counted as one unique pair.
(Note that the word "semordnilap" is not in the above dictionary.)

Solution:
>>> with open('unixdict.txt') as f:
	wordset = set(f.read().strip().split())

>>> revlist = (''.join(word[::-1]) for word in wordset)
>>> pairs   = set((word, rev) for word, rev in zip(wordset, revlist)
                  if word < rev and rev in wordset)
>>> len(pairs)
158
>>> sorted(pairs, key=lambda p: (len(p[0]), p))[-5:]
[('damon', 'nomad'), ('lager', 'regal'), ('leper', 'repel'), ('lever', 'revel'), ('kramer', 'remark')]
>>>


Semordnilap

Solution:
'''Dictionary words paired by equivalence under reversal'''

from functools import (reduce)
from itertools import (chain)
import urllib.request

# semordnilaps :: [String] -> [String]
def semordnilaps(xs):
    '''The subset of words in a list which
       are paired (by equivalence under reversal)
       with other words in that list.
    '''
    def go(tpl, w):
        (s, ws) = tpl
        if w[::-1] in s:
            return (s, ws + [w])
        else:
            s.add(w)
            return (s, ws)
    return reduce(go, xs, (set(), []))[1]

# TEST ----------------------------------------------------
def main():
    '''Test'''

    url = 'http://wiki.puzzlers.org/pub/wordlists/unixdict.txt'
    ws = semordnilaps(
        urllib.request.urlopen(
            url
        ).read().splitlines()
    )
    print(
        fTable(
            __doc__ + ':\n\n(longest of ' +
            str(len(ws)) + ' in ' + url + ')\n'
        )(snd)(fst)(identity)(
            sorted(
                concatMap(
                    lambda x: (
                        lambda s=x.decode('utf8'): [
                            (s, s[::-1])
                        ] if 4 < len(x) else []
                    )()
                )(ws),
                key=compose(len)(fst),
                reverse=True
            )
        )
    )

# GENERIC -------------------------------------------------

# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
    '''Right to left function composition.'''
    return lambda f: lambda x: g(f(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).'''
    return lambda xs: list(
        chain.from_iterable(map(f, xs))
    )

# FORMATTING ----------------------------------------------

# fTable :: String -> (a -> String) ->
#                     (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function -> fx display function ->
                     f -> xs -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )

# fst :: (a, b) -> a
def fst(tpl):
    '''First member of a pair.'''
    return tpl[0]

# identity :: a -> a
def identity(x):
    '''The identity function.'''
    return x

# snd :: (a, b) -> b
def snd(tpl):
    '''Second member of a pair.'''
    return tpl[1]

if __name__ == '__main__':
    main()


Sequence: nth number with exactly n divisors

Calculate the sequence where each term an is the nth that has '''n''' divisors.

;Task

Show here, on this page, at least the first '''15''' terms of the sequence.

;See also

:*OEIS:A073916

;Related tasks

:*[[Sequence: smallest number greater than previous term with exactly n divisors]]
:*[[Sequence: smallest number with exactly n divisors]]

Solution:
def divisors(n):
    divs = [1]
    for ii in range(2, int(n ** 0.5) + 3):
        if n % ii == 0:
            divs.append(ii)
            divs.append(int(n / ii))
    divs.append(n)
    return list(set(divs))

def is_prime(n):
    return len(divisors(n)) == 2

def primes():
    ii = 1
    while True:
        ii += 1
        if is_prime(ii):
            yield ii

def prime(n):
    generator = primes()
    for ii in range(n - 1):
        generator.__next__()
    return generator.__next__()

def n_divisors(n):
    ii = 0
    while True:
        ii += 1
        if len(divisors(ii)) == n:
            yield ii

def sequence(max_n=None):
    if max_n is not None:
        for ii in range(1, max_n + 1):
            if is_prime(ii):
                yield prime(ii) ** (ii - 1)
            else:
                generator = n_divisors(ii)
                for jj, out in zip(range(ii - 1), generator):
                    pass
                yield generator.__next__()
    else:
        ii = 1
        while True:
            ii += 1
            if is_prime(ii):
                yield prime(ii) ** (ii - 1)
            else:
                generator = n_divisors(ii)
                for jj, out in zip(range(ii - 1), generator):
                    pass
                yield generator.__next__()

if __name__ == '__main__':
    for item in sequence(15):
        print(item)


Sequence: smallest number greater than previous term with exactly n divisors

Calculate the sequence where each term an is the '''smallest natural number''' greater than the previous term, that has exactly '''n''' divisors.

;Task
Show here, on this page, at least the first '''15''' terms of the sequence.

;See also
:* OEIS:A069654

;Related tasks
:* [[Sequence: smallest number with exactly n divisors]]
:* [[Sequence: nth number with exactly n divisors]]

Solution:
def divisors(n):
    divs = [1]
    for ii in range(2, int(n ** 0.5) + 3):
        if n % ii == 0:
            divs.append(ii)
            divs.append(int(n / ii))
    divs.append(n)
    return list(set(divs))

def sequence(max_n=None):
    previous = 0
    n = 0
    while True:
        n += 1
        ii = previous
        if max_n is not None:
            if n > max_n:
                break
        while True:
            ii += 1
            if len(divisors(ii)) == n:
                yield ii
                previous = ii
                break

if __name__ == '__main__':
    for item in sequence(15):
        print(item)