2

I have the following numpy array

import numpy as np
a = np.array([1,2,6,8])

I want to create another numpy array from a such that it contains all the different possible sums of TWO elements of a. It's easy to show then that there are int(a.size*(a.size-1)/2) different possible sums, composed from:

a[0] + a[1]
a[0] + a[2]
a[0] + a[3]
a[1] + a[2]
a[1] + a[3]
a[2] + a[3]

How can I construct a numpy array with the above sums as elements without using a double for loop (the only way I can think of it). For the above example, the output should be [3,7,9,8,10,14]

MWE

eff = int(a.size*(a.size-1)/2)
c = np.empty((0, eff))

3 Answers 3

5

You can use triu_indices:

i0,i1 = np.triu_indices(4,1)
a[i0]
# array([1, 1, 1, 2, 2, 6])
a[i1]
# array([2, 6, 8, 6, 8, 8])
a[i0]+a[i1]
# array([ 3,  7,  9,  8, 10, 14])

For more terms we need to build our own "nd_triu_idx". Here is how to do it for 3 terms out of a list of 5:

n = 5
full = np.mgrid[:n,:n,:n]
nd_triu_idx = full[:,(np.diff(full,axis=0)>0).all(axis=0)]
nd_triu_idx
# array([[0, 0, 0, 0, 0, 0, 1, 1, 1, 2],
#        [1, 1, 1, 2, 2, 3, 2, 2, 3, 3],
#        [2, 3, 4, 3, 4, 4, 3, 4, 4, 4]])

To fully generalize the number of terms use something like

k = 4
full = np.mgrid[k*(slice(n),)]

etc.

Sign up to request clarification or add additional context in comments.

8 Comments

This is the great! Can it easily be adapted to find all combinations of three element sums?
So for sum of three elements of the array shown in the OP, I expect to see something like [9,11,15,16]. How do I explicitly get this from your updated code? And how does it generalise to more terms (max number of terms is 4 for the question)
@Sid in that case you'd have to replace n=5 with n=4 and add as the last line a[nd_triu_idx].sum(axis=0)
@PaulPanzer, Thanks. Finally, if I wanted to do it for 4 terms out of a list of 5, would I just change the first two lines? n = 5 full = np.mgrid[:n,:n,:n,:n]? If so is there a way to specify the result for the number of terms and the size of the list?
@Sid If you don't care about the order of the sums, the easiest way of getting all of them would be np.unpackbits(np.arange(1024,dtype='<u2')[:,None].view('u1'),axis=1,count=10,bitorder='little')@a
|
2

You can do combinations on your array of size 2 and sum each one:

import numpy as np
from itertools import combinations

a = np.array([1,2,6,8])

print(list(map(sum, combinations(a, 2))))
# [3, 7, 9, 8, 10, 14]

Or using numpy:

import numpy as np

a = np.array([1,2,6,8,1])

b = a + a[:,None]
print(b[np.triu_indices(4, 1)])
# [ 3  7  9  8 10 14]

6 Comments

Since i'll be using the list, is it possible to write b = list(map(sum, combinations(a, 2)))?
Good case for np.fromiter() if you want a NumPy array back: np.fromiter(map(sum, it.combinations(a, 2)), dtype=a.dtype)
I'm getting a TypeError: 'list' object is not callable error.
@Sid, Make sure you don't name your list as list.
@Sid, You have previously defined some list with some built-ins I used in my code. It can be either list or map. Please check.
|
0

What about computing the cartesian product of exponentiated version of a?

>>> a = np.array([1, 2, 6, 8])[:, None]
>>> b = np.exp(a)
>>> np.unique(np.tril(np.log(np.dot(b, b.T)), k=-1))[1:]
array([ 3.,  7.,  8.,  9., 10., 14.])

2 Comments

This doesn't have the correct length. Should be a 1 by 6 array
This is not quite right (still has an extra zero in in), but fairly clever (and convoluted), so +1

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.