Franck Dernoncourt
Franck Dernoncourt

Reputation: 83187

Cartesian product whose output is not in lexicographic ordering

I want do a Cartesian product between severable iterables in Python and I would like to specify the order of the iteration.

E.g. I have 3 iterables: 'AB', 'xy', '01' in my example. When I write

import itertools
print list(itertools.product('AB', 'xy', '01')) 

the output is in lexicographic order:

('A', 'x', '0')
('A', 'x', '1')
('A', 'y', '0')
('A', 'y', '1')
('B', 'x', '0')
('B', 'x', '1')
('B', 'y', '0')
('B', 'y', '1')

I would like to be able to specify that I want to first iterate on iterable 1 ( 'AB'), then iterable 3 ( '01'), then iterable 2 ( 'xy'), which would give the following output:

('A', 'x', '0')
('B', 'x', '0')
('A', 'x', '1')
('B', 'x', '1')
('A', 'y', '0')
('B', 'y', '0')
('A', 'y', '1')
('B', 'y', '1')

Is there any standard way to do it in Python? I'm OK to use Numpy.

Upvotes: 1

Views: 171

Answers (1)

BrenBarn
BrenBarn

Reputation: 251378

Just pass the iterables in the order you want them to be iterated (or rather, with your terminology, the reverse order --- the first one passed will be the outermost iteration, so it will cycle "slowest"). If you must have the result tuples in a different order, just swap the results afterwards:

>>> [(c, a, b) for a, b, c in itertools.product('xy', '01', 'AB')]
[(u'A', u'x', u'0'),
 (u'B', u'x', u'0'),
 (u'A', u'x', u'1'),
 (u'B', u'x', u'1'),
 (u'A', u'y', u'0'),
 (u'B', u'y', u'0'),
 (u'A', u'y', u'1'),
 (u'B', u'y', u'1')]

Note this doesn't require any extra pass over the results: each tuple is swapped as it is generated.

Upvotes: 3

Related Questions