How to substitute two numpy subarrays with a single one
<p>is there a simple solution to substitute two numpy subarrays with a single one while the entires are a results of functions being called on the entries of the two former arrays. E.g:</p>

<pre><code>[1, a, b][1, c, d] -&gt; [1, f_add, f_sub] 
</code></pre>

<p>with </p>

<pre><code>f_add(a, b, c, d):
    return a + b + c + d

f_sub(b, d):
    return b-d
</code></pre>

<p>Concrete: </p>

<pre><code> [1, 0, 50], [1, 3, 1] -&gt; [1, 54, 49]
</code></pre>

<p>As an addition, the row <code>[1, 0, 50], [1, 3, 1]</code> is part of a bigger array (1st row in example), so it should be substituted in-place</p>

<pre><code>([[1, 0, 50], [2, 0, 50], [1, 3.0, 1.0]],
 [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]])


([[1, 54, 49], [2, 0, 50]],
 [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]])
</code></pre>

<p>Thanks!</p>

<p>EDIT:</p>

<p>The functions f_add and f_sub are just examples to illustrate what I want to do and that the change in entries is a result of functions being called.
In reality I use slightly more complex functions that carry out a (more) meaningful computation.</p>

<p>The second thing is that this substitution should only be carried out on elements where the first entry is the same. 
So in the first row only <code>[1, 0. 50.]</code> and <code>[1, 3.0, 1.0]</code> merge while in the second it would be <code>[2, 0., 50.]</code> and <code>[2, 30, 1.0)</code>.</p>

<p>In this example I first wanted to separate the issue of determining which sub-arrays are intended to merge by comparing the indicies but I guess it should be included to be as general as possible.</p>

<p>A more complete example result to the one above would be as following then:</p>

<pre><code> ([[1, 0., 50.], [2, 0., 50], [1, 3.0, 1.0]],
 [[1, 0., 50.], [2, 0., 50.], [2, 3.0, 1.0]])
</code></pre>

<p>leading to:</p>

<pre><code>([[1, 54., 49.], [2, 0., 50.]],
 [[1, 0., 50.], [2, 54., 49.]])
</code></pre>

<p>Here's a function to perform the first (inner most) step, assuming the 2 inputs are lists:</p>

<pre><code>def merge(a,b):
    res = [a[0]]  # test b[0] is same?
    abcd = a[1:]+b[1:]   # list join  
    # use np.concatenate here is a,b are arrays
    res.append(f_add(*abcd))
    res.append(f_sum(a[2],b[2]))
    return res
def f_add(a,b,c,d):
    return a+b+c+d
def f_sum(b,d):
    return b-d

In [484]: merge([1,0,50],[1,3,1])
Out[484]: [1, 54, 49]
</code></pre>

<p>With this mixed use of elements, and general functions there isn't much point to treating these as arrays.</p>

<p>Then write a function to handle a 'row', the list of lists where lists with the same <code>x[0]</code> id are to be merged.  The easiest way to collect matching pairs (are there only pairs?) is with a <code>defaultdict</code>.</p>

<p>So I find the pairs; and the merge them with the above function.</p>

<pre><code>def subs(alist):
    # collect the matching ids
    from collections import defaultdict
    dd = defaultdict(list)
    for i,x in enumerate(alist):
        dd[x[0]].append(x)
    # merge pairs
    for i in dd.keys():
        if len(dd[i])==2:
           dd[i]=merge(dd[i][0],dd[i][1])
        elif len(dd[i])==1:
           dd[i]=dd[i][0]  # flatten
        else:
           pass  # do nothing with triplets etc.
    return list(dd.values())

In [512]: lll= [[[1, 0, 50], [2, 0, 50], [1, 3.0, 1.0]],
     ...:  [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]]]

In [513]: [subs(l) for l in lll]
Out[513]: [[[1, 54.0, 49.0], [2, 0, 50]], 
           [[1, 0, 50], [2, 54.0, 49.0]]]
</code></pre>

<p>The <code>lll</code> could be turned into a 3d array:</p>

<pre><code>In [523]: arr=np.array(lll)
In [524]: arr
Out[524]: 
array([[[  1.,   0.,  50.],
        [  2.,   0.,  50.],
        [  1.,   3.,   1.]],

       [[  1.,   0.,  50.],
        [  2.,   0.,  50.],
        [  2.,   3.,   1.]]])
</code></pre>

<p>and the ids we want to mix and match are:</p>

<pre><code>In [525]: arr[:,:,0]
Out[525]: 
array([[ 1.,  2.,  1.],
       [ 1.,  2.,  2.]])
</code></pre>

<p>A pair to be merged is</p>

<pre><code>In [526]: arr[0,[0,2],:]
Out[526]: 
array([[  1.,   0.,  50.],
       [  1.,   3.,   1.]])
</code></pre>

<p>and the 2 mergers:</p>

<pre><code>In [527]: merge(*arr[0,[0,2],:].tolist())
Out[527]: [1.0, 54.0, 49.0]
In [528]: merge(*arr[1,[1,2],:].tolist())
Out[528]: [2.0, 54.0, 49.0]
</code></pre>

<p>But identifying these pairs, and performing the mergers and building a new array is no easier with arrays than it was with the lists.</p>

<pre><code>In [532]: np.array([subs(l.tolist()) for l in arr])
Out[532]: 
array([[[  1.,  54.,  49.],
        [  2.,   0.,  50.]],

       [[  1.,   0.,  50.],
        [  2.,  54.,  49.]]])
</code></pre>

python arrays numpy