0

(First, I chose to do this in Python because I never programmed in it and it would be good practice.)

Someone asked me to implement a little "combination" program that basically outputs all possible combinations of a set of group of numbers. Example, if you have:
(1,2,3) as the first set,
(4,5,6) as the second, and
(7,8,9) as the third, then one combination would be (1,4,7) and so on, with a total of 27 possible combinations. This person just wants to do a 6rows x 6cols matrix or a 5rows x 6cols matrix. However, I want to make my little program as flexible as possible.
The next requirement is to only output combinations with X even numbers. If he wants 0 even numbers, then a possible combination would be (1,5,7). You get the idea. For the permutation part, I used itertools.product(), which works perfectly. It would be easy if I just assume that the number of numbers in each set (cols) is fixed as 6. In that case, I could manually create 6 lists and append each combination to the right list. However and again, I want this to work with N number of cols.

I'm thinking of 2 ways I might be able to do this, but tried with no luck. So my question is: How can I create?

li_1 = [] 
li_2 = [] 
...
li_x = [] 

The one way I tried using "lists of lists":

for combination in itertools.product(*li):
    total_combinations = total_combinations + 1
    #Counts number of even numbers in a single combination
    for x in range(numberInRows):
        if combination[x] % 2 == 0:
            even_counter = even_counter + 1
    print "Even counter:",even_counter
    num_evens[even_counter].append(combination)
    print "Single set:",num_evens
    even_counter = 0

    print combination
print "Num_evens:",num_evens

print '\nTotal combinations:', total_combinations
4
  • 1
    Post the code from the 2 ways you tried Commented Aug 12, 2010 at 21:09
  • I'm going with Andre's answer, although Aaron's seems very similar. If possible, could anyone point out where I'm doing wrong in my code and how I can fix it? Commented Aug 12, 2010 at 21:47
  • You should be zeroing even_counter at the top of the loop, not the bottom Commented Aug 12, 2010 at 22:04
  • Ok, I put the even_counter at the top now. But I still get problems. For the first iteration, after appending, the content of num_evens is: [[(1,4,7)],[(1,4,7)],[(1,4,7)],[(1,4,7)]]. Why are there 4? Shouldn't it be only [[],[(1,4,7)],[],[]] ? Commented Aug 13, 2010 at 3:46

3 Answers 3

1
num_evens = {} 
for combination in itertools.product(*li):
    even_counter = len([ y for y in combination if y & 1 == 0 ])
    num_evens.setdefault(even_counter,[]).append(combination)

import pprint
pprint.pprint(num_evens)
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, it worked. Could you kindly explain to me the two lines inside the for loop? Specifically the "len" part and the "setdefault(even_counter,[])".
compact code is not necessarily the most readable, I admit :-) The first line inside the loop calculates the length of the list in brackets. The construct with the brackets is called 'list comprehension' (see en.wikipedia.org/wiki/List_comprehension#Python). It constructs a list with the expression given (y in this case but could be more complicated) for all elements in the collection given (combination in this case) under the given condition (y must be even). Try print [ y for y in combination if y & 1 == 0] should make clear what I mean. [ y for y in combination
Building a whole list just to take its len isn't necessary, which is why I used sum and a generator expression instead.
The second line in the loop sets an entry in the dict 'num_evens'. This dict (in our case here) maps from a number (key) to a list of tuples (value). Now if you want to append 'combination' to the list associated to the key 'even_counter' one must make sure that there is at least an empty list (one can't append to 'None') for the given key. This is what setdefault ensures: if 'even_counter' is not yet in the dict 'num_evens', it first puts the second argument (an empty list in this example) into the dict and then returns it (or returns the value which was already in the dict before).
Ah... I get it. I just find it strange why my own code is not outputting correctly. It seems like the same basic logic.
|
1
Ls = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
import collections
import itertools

def products_by_even_count(seq):
    ret = collections.defaultdict(set)
    for p in itertools.product(*seq):
        n_even = sum(1 for n in p if n % 2 == 0)
        ret[n_even].add(p)
    return ret

import pprint
# Calling dict() is only necessary for pretty pprint output.
pprint.pprint(dict(products_by_even_count(Ls)))

Output:

{0: set([(1, 5, 7), (1, 5, 9), (3, 5, 7), (3, 5, 9)]),
 1: set([(1, 4, 7),
         (1, 4, 9),
         (1, 5, 8),
         (1, 6, 7),
         (1, 6, 9),
         (2, 5, 7),
         (2, 5, 9),
         (3, 4, 7),
         (3, 4, 9),
         (3, 5, 8),
         (3, 6, 7),
         (3, 6, 9)]),
 2: set([(1, 4, 8),
         (1, 6, 8),
         (2, 4, 7),
         (2, 4, 9),
         (2, 5, 8),
         (2, 6, 7),
         (2, 6, 9),
         (3, 4, 8),
         (3, 6, 8)]),
 3: set([(2, 4, 8), (2, 6, 8)])}

Comments

1
from itertools import product
from collections import defaultdict
num_evens = defaultdict(list)
for comb in product(*li):
    num_evens[sum(y%2==0 for y in comb)].append(comb)

import pprint
pprint.pprint(num_evens)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.