Question

My question is simple: "how to build a dynamic growing truth table in python in an elegant way?"

for n=3

for p in False, True:
    for q in False, True:
        for r in False, True:
            print '|{0} | {1} | {2} |'.format(int(p),int(q), int(r))

for n=4

for p in False, True:
    for q in False, True:
        for r in False, True:
            for s in False, True:
                print '|{0} | {1} | {2} | {3}'.format(int(p),int(q), int(r), int(s))

I would like to have a function which takes n as a parameter and builds up the table, it is not necessary to print the table, returning a data structure representing the table is fine also.

Was it helpful?

Solution

Use itertools.product():

table = list(itertools.product([False, True], repeat=n))

Result for n = 3:

[(False, False, False),
 (False, False, True),
 (False, True, False),
 (False, True, True),
 (True, False, False),
 (True, False, True),
 (True, True, False),
 (True, True, True)]

OTHER TIPS

itertools really is the way to go as has been pointed out by everyone. But if you really want to see the nuts and bolts of the algorithm required for this, you should look up recursive descent. Here's how it would work in your case:

def tablize(n, truths=[]):
    if not n:
        print truths
    else:
        for i in [True, False]:
            tablize(n-1, truths+[i])

Tested, working

Hope this helps

List comprehensions are, of course, more Pythonic.

def truthtable (n):
  if n < 1:
    return [[]]
  subtable = truthtable(n-1)
  return [ row + [v] for row in subtable for v in [0,1] ]

Results, indented for clairity:

truthtable(1)
[ [0],
  [1] ]

truthtable(3)
[ [0, 0, 0],
  [0, 0, 1],
  [0, 1, 0],
  [0, 1, 1],
  [1, 0, 0],
  [1, 0, 1],
  [1, 1, 0],
  [1, 1, 1] ]

As a generator function with yield:

def truthtable (n): 
  if n < 1:
    yield []
    return
  subtable = truthtable(n-1)
  for row in subtable:
    for v in [0,1]:
      yield row + [v]

Also simply changing the return from an array comprehension to a generator expression makes the return type equivalent to the yield version's generator function:

def truthtable (n):
  if n < 1:
    return [[]]
  subtable = truthtable(n-1)
  return ( row + [v] for row in subtable for v in [0,1] )

Have a look at the itertools module

In [7]: [i for i in itertools.product([0,1], repeat=3)]
Out[7]: 
[(0, 0, 0),
 (0, 0, 1),
 (0, 1, 0),
 (0, 1, 1),
 (1, 0, 0),
 (1, 0, 1),
 (1, 1, 0),
 (1, 1, 1)]

returning a datastructure representing the table is fine

...in that case range(2 ** n) is all you need. Each number in the range represents a row in the truth table. The ith bit of the binary representation of the number k is 1 if and only if the ith variable is true in the kth row of the table.

If you want an actual table you can use:

[ [ ((row >> bit_index) & 1) == 1 for bit_index in range(n)] 
  for bit_index in range(2 ** n) ]

who here likes raw 1-liners?

>>> truthtable = lambda n: [[(v>>i)&1 for i in range(n-1,-1,-1)] for v in range(1<<n)] if n>0 else [[]]

100% tested and working.
(can't copy/paste result, or above code, cause I'm on a phone for Internet)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top