Tom
Tom

Reputation: 233

Combining array elements in a particular way, and recording it

I am given a 1D array of numbers.

I need to go through the array adding each consecutive element to form a sum. Once this sum reaches a certain value, it forms the first element of a new array. The sum is then reset and the process repeats, thus iterating over the whole array.

For example if given: [1, 3, 4, 5, 2, 5, 3] and requiring the minimum sum to be 5, the new array would be: [8, 5, 7]

Explicity: [1 + 3 + 4, 5, 2 + 5]

I then also need to keep a record of the way the elements were combined for that particular array: I need to be to take a different array of the same length and combine the elements in the same way as above.

e.g. give the array [1, 2, 1, 1, 3, 2, 1] I require the output [4, 1, 5]

Explicity: [1 + 2 + 1, 1, 3 + 2]

I have accomplished this with i loops and increment counters, but it is very ugly. The array named "record" contains the number of old elements summed to make each element of the new array i.e. [3, 1, 2]

import numpy as np

def bin(array, min_sum):

    num_points = len(array)

    # Create empty output.
    output = list()
    record = list()

    i = 0

    while i < num_points:

        sum = 0
        j = 0

        while sum < min_sum:

            # Break out if it reaches end of data whilst in loop.
            if i+j == num_points:
                break

            sum += array[i+j]

            j += 1

        output.append(sum)
        record.append(j)

        i += j

    # The final data point does not reach the min sum.
    del output[-1]

    return output

if __name__ == "__main__":
    array = [1, 3, 4, 5, 2, 5, 3]
    print bin(array, 5)

Upvotes: 1

Views: 60

Answers (3)

Abr001am
Abr001am

Reputation: 591

You can use short solutions I found out after a long struggle with flattening arrays.

For getting bounded sums use:

f = lambda a,x,j,l: 0 if j>=l else [a[i] for i in range(j,l) if sum(a[j:i])<x]

This outputs:

>>> f = lambda a,x,j,l: 0 if j>=l else [a[i] for i in range(j,l) if sum(a[j:i])< x]
>>> a= [1, 3, 4, 5, 2, 5, 3]
>>> f(a,5,0,7) 
[1, 3, 4]
>>> sum(f(a,5,0,7)) 
8
>>> sum(f(a,5,3,7)) 
5
>>> sum(f(a,5,4,7)) 
7
>>>

To get your records use the function:

>>> y = lambda a,x,f,j,l: [] if j>=l else list(np.append(j,np.array(y(a,x,f,j+len(f(a,x,j,l)),l))))

From here, you can get both array of records and sums:

>>> listt=y(a,5,f,0,len(a))
>>> listt
[0.0, 3.0, 4.0, 6.0]
>>> [sum(f(a,5,int(listt[u]),len(a))) for u in range(0,len(listt)-1)]
[8, 5, 7]
>>>

Now, the bit of magic you can even use it as an index-conditional boundary for the second vector:

>>> b=[1, 2, 1, 1, 3, 2, 1]
>>> [sum(f(b,5,int(listt[u]),int(listt[u+1]))) for u in range(0,len(listt)-1)]
[4, 1, 5]
>>>

Upvotes: 0

jq170727
jq170727

Reputation: 14695

Here is a straightforward solution. which computes a list of boolean values where the value is true when accumulated element equals or exceeds the target value and calc computes an accumulation using this list.

def which(l, s):
    w, a = [], 0
    for e in l:
        a += e
        c = (a >= s)
        w.append(c)
        if c:
            a = 0
    return w

def calc(l, w):
    a = 0
    for (e, c) in zip(l, w):
        a += e
        if c:
            yield a
            a = 0

here is an interactive demonstration

>>> l1 = [1, 3, 4, 5, 2, 5, 3]
>>> w = which(l1, 5)
>>> w
[False, False, True, True, False, True, False]
>>> list(calc(l1, w))
[8, 5, 7]
>>> l2 = [1, 2, 1, 1, 3, 2, 1]
>>> list(calc(l2, w))
[4, 1, 5]

Upvotes: 1

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477230

I would advice you to simply walk through the list. Add it to an accumulator like the_sum (do not use sum, since it is a builtin), and in case the_sum reaches a number higher than the min_sum, you add it, and reset the_sum to zero. Like:

def bin(array, min_sum):
    result = []
    the_sum = 0
    for elem in array:
        the_sum += elem
        if the_sum >= min_sum:
            result.append(the_sum)
            the_sum = 0
    return result

The lines where the accumulator is involved, are put in boldface.

I leave combining the other array the same way as an exercise, but as a hint: use an additional accumulator and zip to iterate over both arrays concurrently.

Upvotes: 1

Related Questions