Python Spikes

Following are “spike” solutions (see SpikeDescribed) for several proposed problems. I’ve kept them here because I like their elegance. — Scott Moonen


In September 2007, Brian Adkins posted a simple Logo program to print all possible combinations of lists of items, and asked for alternatives in other languages. He provided a Ruby alternative which would translate fairly easily into Python. For my own Python implementation I decided to try a completely different approach:

optstr  = lambda x : (type(x)==str)*str(x)+(type(x)!=str)*' '.join(x)
prod1   = lambda elem, vec : map(lambda x : optstr(elem)+' '+optstr(x), vec)
xprod   = lambda vec1, vec2 : reduce(list.__add__, map(lambda elem : prod1(elem ,vec2), vec1))
choices = lambda x : '\n'.join(reduce(xprod, x))+'\n'

q = [['small', 'medium', 'large'],
     ['vanilla', ['ultra', 'chocolate'], 'lychee', ['rum', 'raisin'], 'ginger'],
     ['cone', 'cup']]

print choices(q),

Brian tells me that I took Logo too literally in translating ‘ultra chocolate’ to a sublist. Removing that reduces my implementation to three lines:

prod1   = lambda elem, vec : map(lambda x : elem+' '+x, vec)
xprod   = lambda vec1, vec2 : reduce(list.__add__, map(lambda elem : prod1(elem ,vec2), vec1))
choices = lambda x : '\n'.join(reduce(xprod, x))+'\n'

q = [['small', 'medium', 'large'],
     ['vanilla', 'ultra chocolate', 'lychee', 'rum raisin', 'ginger'],
     ['cone', 'cup']]

print choices(q),

I crafted this compact solution to Dijkstra’s OddWordProblem:

from sys import stdin, stdout
def even(char) : stdout.write(char); return select(even, 0, "");
def odd(char)  : q = select(odd, 0, ""); stdout.write(char); return q
def select(fn, skipspace, prefix) :
 char = stdin.read(1)
 if char.isspace() and skipspace : return select(fn, 1, prefix)
 elif char.isspace()             : return 0
 elif char.isalpha()             : stdout.write(prefix); return fn(char)
 elif char == "."                : return 1
 else                            : raise "Invalid input"

if not select(even, 1, "") :
 while not select(odd, 1, " ") and not select(even, 1, " ") : pass
stdout.write(".")

I came up with these simple solutions to RonJeffriesCodingProblem. The first uses Python 2.2’s generators:

def split(list, num) :
  for index in range(num) :
    yield list[index * len(list) / num:(index + 1) * len(list) / num]

I prefer the second, which uses the functional idiom:

def split(list, num) :
  return map(lambda x: list[x * len(list) / num:(x+1) * len(list) / num], range(num))

I composed this concise solution to ncm’s “coding challenge” in November 2004. I’m not entirely satisfied with its elegance, but I’m pleased with its brevity.

def dateinc(s) :
  def carry(list, modulus) :
    if len(list) == 1 : return [list[0] // modulus[0], list[0] % modulus[0]]
    else              : q = carry(list[1:], modulus[1:]); return [(list[0] + q[0]) // modulus[0], (list[0] + q[0]) % modulus[0]] + q[1:]
 s = reduce(lambda x,y:x+y, map(lambda x : (x >= '0' and x <= '9') * x, s))
  result = map(lambda x,y:x+y, map(int,(s[0:4],s[4:6],s[6:8],s[8:10],s[10:12],s[12:14])),(0,-1,-1,0,0,1))
  modulus = [10000,12,[31,28,31,30,31,30,31,31,30,31,30,31][result[1]],24,60,60]
  if result[0] % 4 == 0 and (result[0] % 100 != 0 or result[0] % 400 == 0) :
    modulus[2] += 1                               # Account for leap day.
  result = carry(result, modulus)[1:]             # Carry the extra second.
  result[1:3] = map(lambda x:x+1, result[1:3])    # Readjust to 1-base.
 return reduce(lambda x,y:x+y, map(lambda x : (x < 10) * '0' + str(x), result))

I further reduced this as follows, turning the carry function into a one-liner that computes the carry in-place (and also using builtins wherever possible). I’m much more satisfied with this solution.

def dateinc(s) :
  s = reduce(lambda x,y:x.isdigit()*x+y.isdigit()*y, s)
  ans = map(int.__add__, map(int,(s[0:4],s[4:6],s[6:8],s[8:10],s[10:12],s[12:14])),(0,-1,-1,0,0,1))
  mod = [10000,12,[31,28,31,30,31,30,31,31,30,31,30,31][ans[1]],24,60,60]
  if ans[0] % 4 == 0 and (ans[0] % 100 != 0 or ans[0] % 400 == 0) : mod[2] += 1
  ans = map(lambda x:(ans[x] + reduce(int.__mul__, map(lambda y:ans[y]>=mod[y]-1,range(x+1,len(ans))),x!=len(ans)-1)) % mod[x], range(len(ans)))
  ans[1:3] = map(int.__add__,ans[1:3],[1,1])      # Readjust to 1-base.
 return reduce(str.__add__, map(lambda x : (x < 10) * '0' + str(x), ans))
Visit my other blogs: truth, adorned, finance and stuff.