A custom list that when multiplied by other list returns a cartesian product... the good thing is that the cartesian product is indexable, not like that of itertools.product (but the multiplicands must be sequences, not iterators).
import operator
class mylist(list):
def __getitem__(self, args):
if type(args) is tuple:
return [list.__getitem__(self, i) for i in args]
else:
return list.__getitem__(self, args)
def __mul__(self, args):
seqattrs = ("__getitem__", "__iter__", "__len__")
if all(hasattr(args, i) for i in seqattrs):
return cartesian_product(self, args)
else:
return list.__mul__(self, args)
def __imul__(self, args):
return __mul__(self, args)
def __rmul__(self, args):
return __mul__(args, self)
def __pow__(self, n):
return cartesian_product(*((self,)*n))
def __rpow__(self, n):
return cartesian_product(*((self,)*n))
class cartesian_product:
def __init__(self, *args):
self.elements = args
def __len__(self):
return reduce(operator.mul, map(len, self.elements))
def __getitem__(self, n):
return [e[i] for e, i in zip(self.elements,self.get_indices(n))]
def get_indices(self, n):
sizes = map(len, self.elements)
tmp = [0]*len(sizes)
i = -1
for w in reversed(sizes):
tmp[i] = n % w
n /= w
i -= 1
return tmp
def __add__(self, arg):
return mylist(map(None, self)+mylist(map(None, arg)))
def __imul__(self, args):
return mylist(self)*mylist(args)
def __rmul__(self, args):
return mylist(args)*mylist(self)
def __mul__(self, args):
if isinstance(args, cartesian_product):
return cartesian_product(*(self.elements+args.elements))
else:
return cartesian_product(*(self.elements+(args,)))
def __iter__(self):
for i in xrange(len(self)):
yield self[i]
def __str__(self):
return "[" + ",".join(str(i) for i in self) +"]"
def __repr__(self):
return "*".join(map(repr, self.elements))