python creating convolve function for arrays - python

I have two arrays,
a = [3, 6, 8, 2, 5, 5]
b = [2, 7, 9]
and I need to create a new array c which takes the values and adds them like this: a[0+0]*b[0] + a[0+1]*b[1] + a[0+2]*b[2] = (3*2) + (6*7) + (9*8) = 6 + 42 + 72 which means c[0] = 120
I'm completely lost on how to do this anything to point me in the right direction would be awesome.

If c[k] = a[k+0]*b[0] + a[k+1]*b[1] + a[k+2]*b[2]
then
>>> c = [sum(i*j for i,j in zip(a[k:], b)) for k in range(4)]
>>> c
[120, 86, 75, 84]

total = 0
for n in range(0, min(len(a), len(b))):
total += a[n] * b[n]
range function

I think this will do what you want. It borrows some of the code from #DukeSilver's answer and makes it build a list, rather than just calculating a single value. My assumption is that a is always longer than b.
c = [sum(a[i+j]*b[j] for j in range(len(b))) for i in range(len(a) - len(b) + 1)]

numpy.convolve or do you want to write your own function?

Related

Remove values from numpy array closer to each other

Actually i want to remove the elements from numpy array which are closer to each other.For example i have array [1,2,10,11,18,19] then I need code that can give output like [1,10,18] because 2 is closer to 1 and so on.
In the following is provided an additional solution using numpy functionalities (more precisely np.ediff1d which makes the differences between consecutive elements of a given array. This code considers as threshold the value associated to the th variable.
a = np.array([1,2,10,11,18,19])
th = 1
b = np.delete(a, np.argwhere(np.ediff1d(a) <= th) + 1) # [1, 10, 18]
Here is simple function to find the first values of series of consecutives values in a 1D numpy array.
import numpy as np
def find_consec(a, step=1):
vals = []
for i, x in enumerate(a):
if i == 0:
diff = a[i + 1] - x
if diff == step:
vals.append(x)
elif i < a.size-1:
diff = a[i + 1] - x
if diff > step:
vals.append(a[i + 1])
return np.array(vals)
a = np.array([1,2,10,11,18,19])
find_consec(a) # [1, 10, 18]
Welcome to stackoverflow. below is the code that can answer you question:
def closer(arr,cozy):
result = []
result.append(arr[0])
for i in range(1,len(arr)-1):
if arr[i]-result[-1]>cozy:
result.append(arr[i])
print result
Example:
a = [6,10,7,20,21,16,14,3,2]
a.sort()
closer(a,1)
output : [2, 6, 10, 14, 16, 20]
closer(a,3)
Output: [2, 6, 10, 14, 20]

Divide the list into three lists such that their sum are close to each other

Let's say that I have an array of number S = [6, 2, 1, 7, 4, 3, 9, 5, 3, 1]. I want to divide into three arrays. The order of the number and the number of item in those array does not matter.
Let's say A1, A2, and A3 are the sub arrays. I want to minimize the function
f(x) = ( SUM(A1) - SUM(S) / 3 )^2 / 3 +
( SUM(A2) - SUM(S) / 3 )^2 / 3 +
( SUM(A3) - SUM(S) / 3 )^2 / 3
I don't need an optimal solution; I just need the solution that is good enough.
I don't want an algorithm that is too slow. I can trade some speed for a better result, but I cannot trade too much.
The length of S is around 10 to 30.
Why
Why do I need to solve this problem? I want to nicely arrange the box into three columns such that the total height of each columns is not too different from each other.
What have I tried
My first instinct is to use greedy. The result is not that bad, but it does not ensure an optimal solution. Is there a better way?
s = [6, 2, 1, 7, 4, 3, 9, 5, 3, 1]
s = sorted(s, reverse=True)
a = [[], [], []]
sum_a = [0, 0, 0]
for x in s:
i = sum_a.index(min(sum_a))
sum_a[i] += x
a[i].append(x)
print(a)
As you said you don't mind a non-optimal solution, I though I would re-use your initial function, and add a way to find a good starting arrangement for your initial list s
Your initial function:
def pigeon_hole(s):
a = [[], [], []]
sum_a = [0, 0, 0]
for x in s:
i = sum_a.index(min(sum_a))
sum_a[i] += x
a[i].append(x)
return map(sum, a)
This is a way to find a sensible initial ordering for your list, it works by creating rotations of your list in sorted and reverse sorted order. The best rotation is found by minimizing the standard deviation, once the list has been pigeon holed:
def rotate(l):
l = sorted(l)
lr = l[::-1]
rotation = [np.roll(l, i) for i in range(len(l))] + [np.roll(lr, i) for i in range(len(l))]
blocks = [pigeon_hole(i) for i in rotation]
return rotation[np.argmin(np.std(blocks, axis=1))] # the best rotation
import random
print pigeon_hole(rotate([random.randint(0, 20) for i in range(20)]))
# Testing with some random numbers, these are the sums of the three sub lists
>>> [64, 63, 63]
Although this could be optimized further it is quite quick taking 0.0013s for 20 numbers. Doing a quick comparison with #Mo Tao's answer, using a = rotate(range(1, 30))
# This method
a = rotate(range(1, 30))
>>> [[29, 24, 23, 18, 17, 12, 11, 6, 5], [28, 25, 22, 19, 16, 13, 10, 7, 4, 1], [27, 26, 21, 20, 15, 14, 9, 8, 3, 2]]
map(sum, a)
# Sum's to [145, 145, 145] in 0.002s
# Mo Tao's method
>>> [[25, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [29, 26, 20, 19, 18, 17, 16], [28, 27, 24, 23, 22, 21]]
# Sum's to [145, 145, 145] in 1.095s
This method also seems to find the optimal solution in many cases, although this probably wont hold for all cases. Testing this implementation 500 times using a list of 30 numbers against Mo Tao's answer, and comparing if the sub-lists sum to the same quantity:
c = 0
for i in range(500):
r = [random.randint(1, 10) for j in range(30)]
res = pigeon_hole(rotate(r))
d, e = sorted(res), sorted(tao(r)) # Comparing this to the optimal solution by Mo Tao
if all([k == kk] for k, kk in zip(d, e)):
c += 1
memory = {}
best_f = pow(sum(s), 3)
best_state = None
>>> 500 # (they do)
I thought I would provide an update with a more optimized version of my function here:
def rotate2(l):
# Calculate an acceptable minimum stdev of the pigeon holed list
if sum(l) % 3 == 0:
std = 0
else:
std = np.std([0, 0, 1])
l = sorted(l, reverse=True)
best_rotation = None
best_std = 100
for i in range(len(l)):
rotation = np.roll(l, i)
sd = np.std(pigeon_hole(rotation))
if sd == std:
return rotation # If a min stdev if found
elif sd < best_std:
best_std = sd
best_rotation = rotation
return best_rotation
The main change is that the search for a good ordering stops once a suitable rotation has been found. Also only the reverse sorted list is searched which doesnt appear to alter the result. Timing this with
print timeit.timeit("rotate2([random.randint(1, 10) for i in range(30)])", "from __main__ import rotate2, random", number=1000) / 1000.
results in a large speed up. On my current computer rotate takes about 1.84ms and rotate2 takes about 0.13ms, so about a 14x speed-up. For comparison גלעד ברקן 's implementation took about 0.99ms on my machine.
As I mentioned in the comment of the question, this is the straight-forward dynamic programming method. It takes less than 1 second for s = range(1, 30) and gives optimized solution.
I think the code is self-explained if you known Memoization.
s = range(1, 30)
# s = [6, 2, 1, 7, 4, 3, 9, 5, 3, 1]
n = len(s)
memory = {}
best_f = pow(sum(s), 3)
best_state = None
def search(state, pre_state):
global memory, best_f, best_state
s1, s2, s3, i = state
f = s1 * s1 + s2 * s2 + s3 * s3
if state in memory or f >= best_f:
return
memory[state] = pre_state
if i == n:
best_f = f
best_state = state
else:
search((s1 + s[i], s2, s3, i + 1), state)
search((s1, s2 + s[i], s3, i + 1), state)
search((s1, s2, s3 + s[i], i + 1), state)
search((0, 0, 0, 0), None)
a = [[], [], []]
state = best_state
while state[3] > 0:
pre_state = memory[state]
for j in range(3):
if state[j] != pre_state[j]:
a[j].append(s[pre_state[3]])
state = pre_state
print a
print best_f, best_state, map(sum, a)
We can research the stability of the solution you found with respect to replacing of elements between found lists. Below I placed my code. If we make the target function better by a replacement we keep found lists and go further hoping that we will make the function better again with another replacement. As the starting point we can take your solution. The final result will be something like a local minimum.
from copy import deepcopy
s = [6, 2, 1, 7, 4, 3, 9, 5, 3, 1]
s = sorted(s, reverse=True)
a = [[], [], []]
sum_a = [0, 0, 0]
for x in s:
i = sum_a.index(min(sum_a))
sum_a[i] += x
a[i].append(x)
def f(a):
return ((sum(a[0]) - sum(s) / 3.0)**2 + (sum(a[1]) - sum(s) / 3.0)**2 + (sum(a[2]) - sum(s) / 3.0)**2) / 3
fa = f(a)
while True:
modified = False
# placing
for i_from, i_to in [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]:
for j in range(len(a[i_from])):
a_new = deepcopy(a)
a_new[i_to].append(a_new[i_from][j])
del a_new[i_from][j]
fa_new = f(a_new)
if fa_new < fa:
a = a_new
fa = fa_new
modified = True
break
if modified:
break
# replacing
for i_from, i_to in [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]:
for j_from in range(len(a[i_from])):
for j_to in range(len(a[i_to])):
a_new = deepcopy(a)
a_new[i_to].append(a_new[i_from][j_from])
a_new[i_from].append(a_new[i_to][j_to])
del a_new[i_from][j_from]
del a_new[i_to][j_to]
fa_new = f(a_new)
if fa_new < fa:
a = a_new
fa = fa_new
modified = True
break
if modified:
break
if modified:
break
if not modified:
break
print(a, f(a)) # [[9, 3, 1, 1], [7, 4, 3], [6, 5, 2]] 0.2222222222222222222
It's interesting that this approach works well even if we start with arbitrary a:
from copy import deepcopy
s = [6, 2, 1, 7, 4, 3, 9, 5, 3, 1]
def f(a):
return ((sum(a[0]) - sum(s) / 3.0)**2 + (sum(a[1]) - sum(s) / 3.0)**2 + (sum(a[2]) - sum(s) / 3.0)**2) / 3
a = [s, [], []]
fa = f(a)
while True:
modified = False
# placing
for i_from, i_to in [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]:
for j in range(len(a[i_from])):
a_new = deepcopy(a)
a_new[i_to].append(a_new[i_from][j])
del a_new[i_from][j]
fa_new = f(a_new)
if fa_new < fa:
a = a_new
fa = fa_new
modified = True
break
if modified:
break
# replacing
for i_from, i_to in [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]:
for j_from in range(len(a[i_from])):
for j_to in range(len(a[i_to])):
a_new = deepcopy(a)
a_new[i_to].append(a_new[i_from][j_from])
a_new[i_from].append(a_new[i_to][j_to])
del a_new[i_from][j_from]
del a_new[i_to][j_to]
fa_new = f(a_new)
if fa_new < fa:
a = a_new
fa = fa_new
modified = True
break
if modified:
break
if modified:
break
if not modified:
break
print(a, f(a)) # [[3, 9, 2], [6, 7], [4, 3, 1, 1, 5]] 0.2222222222222222222
It provides a different result but the same value of the function.
I would have to say that your greedy function does produce good results but tends to become very slow if input size is large say more than 100.
But, you've said that your input size is fixed in the range - 10,30. Hence the greedy solution is actually quite good.Instead of becoming all too greedy in the beginning itself.I propose to become a bit lazy at first and become greedy at the end.
Here is a altered function lazy :
def lazy(s):
k = (len(s)//3-2)*3 #slice limit
s.sort(reverse=True)
#Perform limited extended slicing
a = [s[1:k:3],s[2:k:3],s[:k:3]]
sum_a = list(map(sum,a))
for x in s[k:]:
i = sum_a.index(min(sum_a))
sum_a[i] += x
a[i].append(x)
return a
What it does is it first sorts the input in descending order and fills items in three sub-lists one-by-one until about 6 items are left.(You can change this limit and test, but for size 10-30 I think this is the best)
When that is done simply continue with the greedy approach.This method takes very less time and more accurate than the greedy solution on average.
Here is a line plot of size versus time -
and size versus accuracy -
Accuracy is the standard deviation from the mean of final sub-lists and the original list. Because you want the columns to stack up at almost similar height and not at the (mean of the original list) height.
Also, the range of item value is between 3-15 so that sum is around 100-150 as you mentioned.
These are the test functions -
def test_accuracy():
rsd = lambda s:round(math.sqrt(sum([(sum(s)//3-y)**2 for y in s])/3),4)
sm = lambda s:list(map(sum,s))
N=[i for i in range(10,30)]
ST=[]
MT=[]
for n in N:
case = [r(3,15) for x in range(n)]
ST.append(rsd(sm(lazy(case))))
MT.append(rsd(sm(pigeon(case))))
strace = go.Scatter(x=N,y=ST,name='Lazy pigeon')
mtrace = go.Scatter(x=N,y=MT,name='Pigeon')
data = [strace,mtrace]
layout = go.Layout(
title='Uniform distribution in 3 sublists',
xaxis=dict(title='List size',),
yaxis=dict(title='Accuracy - Standard deviation',))
fig = go.Figure(data=data, layout=layout)
plotly.offline.plot(fig,filename='N vs A2.html')
def test_timings():
N=[i for i in range(10,30)]
ST=[]
MT=[]
for n in N:
case = [r(3,15) for x in range(n)]
start=time.clock()
lazy(case)
ST.append(time.clock()-start)
start=time.clock()
pigeon(case)
MT.append(time.clock()-start)
strace = go.Scatter(x=N,y=ST,name='Lazy pigeon')
mtrace = go.Scatter(x=N,y=MT,name='Pigeon')
data = [strace,mtrace]
layout = go.Layout(
title='Uniform distribution in 3 sublists',
xaxis=dict(title='List size',),
yaxis=dict(title='Time (seconds)',))
fig = go.Figure(data=data, layout=layout)
plotly.offline.plot(fig,filename='N vs T2.html')
Here is the complete file.
Edit -
I tested kezzos answer for accuracy and it performed really good. The deviation stayed less than .8 all the time.
Average standard deviation in 100 runs.
Lazy Pigeon Pigeon Rotation
1.10668795 1.1573573 0.54776425
In the case of speed, the order is quite high for rotation function to compare. But, 10^-3 is fine unless you want to run that function repeatedly.
Lazy Pigeon Pigeon Rotation
5.384013e-05 5.930269e-05 0.004980
Here is bar chart comparing accuracy of all three functions. -
All in all, kezzos solution is the best if you are fine with the speed.
Html files of plotly - versus time,versus accuracy and the bar chart.
Here's my nutty implementation of Korf's1 Sequential Number Partitioning (SNP), but it only uses Karmarkar–Karp rather than Complete Karmarkar–Karp for the two-way partition (I've included an unused, somewhat unsatisfying version of CKK - perhaps someone has a suggestion to make it more efficient?).
On the first subset, it places lower and upper bounds. See the referenced article. I'm sure more efficient implementations can be made. Edit MAX_ITERATIONS for better results versus longer wait :)
By the way, the function, KK3 (extension of Karmarkar–Karp to three-way partition, used to compute the first lower bound), seems pretty good by itself.
from random import randint
from collections import Counter
from bisect import insort
from time import time
def KK3(s):
s = list(map(lambda x: (x,0,0,[],[],[x]),sorted(s)))
while len(s) > 1:
large = s.pop()
small = s.pop()
combined = sorted([large[0] + small[2], large[1] + small[1],
large[2] + small[0]],reverse=True)
combined = list(map(lambda x: x - combined[2],combined))
combined = combined + sorted((large[3] + small[5], large[4] +
small[4], large[5] + small[3]),key = sum)
insort(s,tuple(combined))
return s
#s = [6, 2, 1, 7, 4, 3, 9, 5, 3, 1]
s = [randint(0,100) for r in range(0,30)]
# global variables
s = sorted(s,reverse=True)
sum_s = sum(s)
upper_bound = sum_s // 3
lower_bound = sum(KK3(s)[0][3])
best = (sum_s,([],[],[]))
iterations = 0
MAX_ITERATIONS = 10000
def partition(i, accum):
global lower_bound, best, iterations
sum_accum = sum(accum)
if sum_accum > upper_bound or iterations > MAX_ITERATIONS:
return
iterations = iterations + 1
if sum_accum >= lower_bound:
rest = KK(diff(s,accum))[0]
new_diff = sum(rest[1]) - sum_accum
if new_diff < best[0]:
best = (new_diff,(accum,rest[1],rest[2]))
lower_bound = (sum_s - 2 * new_diff) // 3
print("lower_bound: " + str(lower_bound))
if not best[0] in [0,1] and i < len(s) - 1 and sum(accum) + sum(s[i
+ 1:]) > lower_bound:
_accum = accum[:]
partition(i + 1, _accum + [s[i]])
partition(i + 1, accum)
def diff(l1,l2):
return list((Counter(l1) - Counter(l2)).elements())
def KK(s):
s = list(map(lambda x: (x,[x],[]),sorted(s)))
while len(s) > 1:
large = s.pop()
small = s.pop()
insort(s,(large[0] - small[0],large[1] + small[2],large[2] + small[1]))
return s
print(s)
start_time = time()
partition(0,[])
print(best)
print("iterations: " + str(iterations))
print("--- %s seconds ---" % (time() - start_time))
1 Richard E. Korf, Multi-Way Number Partitioning, Computer Science Department, University of California, Los Angeles; aaai.org/ocs/index.php/IJCAI/IJCAI-09/paper/viewFile/625/705

Selection Sort-array sorting

When I run it only the first smallest number gets sorted. Is the problem somewhere in the loops?
def selectionSort(A):
n=len(A)
print(n)
mini=0
for i in range(0,n-2):
mini=i
for j in range(i+1,n-1):
if A[j]<A[mini]:
mini=j
if i!=mini:
temp=A[i]
A[i]=A[mini]
A[mini]=temp
return A
There are actually two issues:
Your second if should be outside the inner for loop.
And your outer and inner loop should be iterating till n-1 and n respectively, instead of n-2 and n-1.
Hence, your code should be like:
def selectionSort(A):
n=len(A)
print(n)
mini=0
for i in range(0,n-1):
mini=i
for j in range(i+1,n):
if A[j]<A[mini]:
mini=j
if i!=mini:
temp=A[i]
A[i]=A[mini]
A[mini]=temp
return A
Output:
>>> selectionSort([2, 5, 7, 1, 3, 0, 10, 43, 21, 32])
10
[0, 1, 2, 3, 5, 7, 10, 21, 32, 43]
Suggestion: You do not need temp variable in python for swapping values. You can simply do it as:
>>> a = 5
>>> b = 3
>>> a, b = b, a
>>> a
3
>>> b
5
In your swapping code, it would be as: A[i], A[mini] = A[mini], A[i]
Yes the problem is in the swapping part of your code, it needs to placed after inner for-loop
def selectionSort(A):
n = len(A)
mini=0
for i in range(0,n-2):
mini=i
for j in range(i+1,n-1):
if A[j]<A[mini]:
mini=j
if i!=mini:
temp=A[i]
A[i]=A[mini]
A[mini]=temp
return A

How to randomly remove a percentage of items from a list

I have two lists of equal length, one is a data series the other is simply a time series. They represent simulated values measured over time.
I want to create a function that removes a set percentage or fraction from both lists but at random. I.e. if my fraction is 0.2, I want to randomly remove 20% of the items from both lists, but they have to be the same items (same index in each list) removed.
For example, let n = 0.2 (20% to be deleted)
a = [0,1,2,3,4,5,6,7,8,9]
b = [0,1,4,9,16,25,36,49,64,81]
After the randomly removed 20%, they become
a_new = [0,1,3,4,5,6,8,9]
b_new = [0,1,9,16,25,36,64,81]
The relationship isn't as straightforward as the example, so I can't just perform this action on one list and then work out the second; they already exist as two lists. And they have to remain in the original order.
Thanks!
import random
a = [0,1,2,3,4,5,6,7,8,9]
b = [0,1,4,9,16,25,36,49,64,81]
frac = 0.2 # how much of a/b do you want to exclude
# generate a list of indices to exclude. Turn in into a set for O(1) lookup time
inds = set(random.sample(list(range(len(a))), int(frac*len(a))))
# use `enumerate` to get list indices as well as elements.
# Filter by index, but take only the elements
new_a = [n for i,n in enumerate(a) if i not in inds]
new_b = [n for i,n in enumerate(b) if i not in inds]
import random
a = [0,1,2,3,4,5,6,7,8,9]
b = [0,1,4,9,16,25,36,49,64,81]
frac = 0.2 # how much of a/b do you want to exclude
new_a, new_b = [], []
for i in range(len(a)):
if random.random()>frac: # with probability, add an element from `a` and `b` to the output
new_a.append(a[i])
new_b.append(b[i])
from random import randint as r
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
percentage = 0.3
g = (r(0, len(a)-1) for _ in xrange(int(len(a) * (1-percentage))))
c, d = [], []
for i in g:
c.append(a[i])
d.append(b[i])
a, b = c, d
print a
print b
If a and b are not very large, you could get away with using zip:
import random
a = [0,1,2,3,4,5,6,7,8,9]
b = [0,1,4,9,16,25,36,49,64,81]
frac = 0.2 # how much of a/b do you want to exclude
ab = list(zip(a,b)) # a list of tuples where the first element is from `a` and the second is from `b`
new_ab = random.sample(ab, int(len(a)*(1-frac))) # sample those tuples
new_a, new_b = zip(*new_ab) # unzip the tuples to get `a` and `b` back
Note that this won't preserve the original order of a and b
You can also operate the zipped a and b sequence, get the random sample of the indexes (to maintain the original order of items) and unzip into a_new and b_new again:
import random
a = [0,1,2,3,4,5,6,7,8,9]
b = [0,1,4,9,16,25,36,49,64,81]
frac = 0.2
c = zip(a, b) # c = list(zip(a, b)) on Python 3
indices = random.sample(range(len(c)), frac * len(c))
a_new, b_new = zip(*sorted(c[i] for i in sorted(indices)))
print(a_new)
print(b_new)
It can print:
(0, 2, 3, 5, 6, 7, 8, 9)
(0, 4, 9, 25, 36, 49, 64, 81)
l = len(a)
n_drop = int(l * n)
n_keep = l - n_drop
ind = [1] * n_keep + [0] * n_drop
random.shuffle(ind)
new_a = [ e for e, i in zip(a, ind) if i ]
new_b = [ e for e, i in zip(b, ind) if i ]

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.
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
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])
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)]

Categories