filippo
filippo

Reputation: 5793

Permutations in python 2.5.2

I have a list of numbers for input, e.g.

671.00   
1,636.00
436.00
9,224.00

and I want to generate all possible sums with a way to id it for output, e.g.:

671.00 + 1,636.00 = 2,307.00
671.00 + 436.00 = 1,107.00
671.00 + 9,224.00 = 9,224.00
671.00 + 1,636.00 + 436.00 = 2,743.00
...

and I would like to do it in Python My current constrains are: a) I'm just learning python now (that's part of the idea) b) I will have to use Python 2.5.2 (no intertools)

I think I have found a piece of code that may help:

def all_perms(str):
    if len(str) <=1:
        yield str
    else:
        for perm in all_perms(str[1:]):
            for i in range(len(perm)+1):
                #nb str[0:1] works in both string and list contexts
                yield perm[:i] + str[0:1] + perm[i:]

( from these guys )

But I'm not sure how to use it in my propose. Could someone trow some tips and pieces of code of help?

cheers,

f.

Upvotes: 1

Views: 1328

Answers (3)

atzz
atzz

Reputation: 18010

Permutations are about taking an ordered set of things and moving these things around (i.e. changing order). Your question is about combinations of things from your list.

Now, an easy way of enumerating combinations is by mapping entries from your list to bits in a number. For example, lets assume that if bit #0 is set (i.e. 1), then number lst[0] participates in the combination, if bit #1 is set, then lst[1] participates in the combination, etc. This way, numbers in range 0 <= n < 2**(len(lst)) identify all possible combinations of lst members, including an empty one (n = 0) and the whole lst (n = 2**(len(lst)) - 1).

You need only combinations of 2 items or more, i.e. only those combination IDs that have at least two nonzero bits in their binary representation. Here is how to identify these:

def HasAtLeastTwoBitsSet(x) :
    return (x & (x-1)) != 0

# Testing:
>>> [x for x in range(33) if HasAtLeastTwoBitsSet(x)]
[3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]

Next step is to extract a combination of list members identified by a combination id. This is easy, thanks to the power of list comprehensions:

def GetSublistByCombination(lst, combination_id) :
    res = [x for (i,x) in enumerate(lst) if combination_id & (1 << i)]
    return res

# Testing:
>>> GetSublistByCombination([0,1,2,3], 1)
[0]
>>> GetSublistByCombination([0,1,2,3], 3)
[0, 1]
>>> GetSublistByCombination([0,1,2,3], 12)
[2, 3]
>>> GetSublistByCombination([0,1,2,3], 15)
[0, 1, 2, 3]

Now let's make a generator that produces all sums, together with their string representations:

def IterAllSums(lst) :
    combinations = [i for i in range(1 << len(lst)) if HasAtLeastTwoBitsSet(i)]
    for comb in combinations :
        sublist = GetSublistByCombination(lst, comb)
        sum_str = '+'.join(map(str, sublist))
        sum_val = sum(sublist)
        yield (sum_str, sum_val)

And, finally, let's use it:

>>> for sum_str, sum_val in IterAllSums([1,2,3,4]) : print sum_str, sum_val

1+2 3
1+3 4
2+3 5
1+2+3 6
1+4 5
2+4 6
1+2+4 7
3+4 7
1+3+4 8
2+3+4 9
1+2+3+4 10

Upvotes: 3

zoli2k
zoli2k

Reputation: 3458

With itertools (Python >=2.6) would be:

from itertools import *
a=[1,2,3,4]
sumVal=[tuple(imap(sum,combinations(a,i))) for i in range(2,len(a)+1)]

Upvotes: 0

phimuemue
phimuemue

Reputation: 35983

The code below generates all "subsets" of a given list (except the empty set), i.e. it returns a list of lists.

def all_sums(l): #assumes that l is non-empty
    if len(l)==1:
        return ([[l[0]]])
    if len(l)==0:
        return []
    result = []
    for i in range(0,len(l)):
        result.append([l[i]])
        for p in all_sums(l[i+1:]):
            result.append([l[i]]+p)
    return result

Now you could just write a short function doit for output also:

def doit(l):
    mylist = all_sums(l)
    print mylist
    for i in mylist:
        print str(i) + " = " + str(sum(i))

doit([1,2,3,4])

Upvotes: 0

Related Questions