19
\$\begingroup\$

The cumulative sum of a vector is calculated by simply taking the sum of all previous elements. For instance:

vec =     [1  1  1 -1 -1 -1 -1 -1  1  1  1  1 -1]
cum_vec = [1  2  3  2  1  0 -1 -2 -1  0  1  2  1]

Now, impose an upper and a lower limit, meaning that you stop increasing the cumulative sum if it's at the upper limit, and stop decreasing the cumulative sum if it's at the lower limit. A simple example:

upper_lim = 2
lower_lim = -1
vec =     [1  1  1 -1 -1 -1 -1 -1  1  1  1  1 -1]
cum_vec = [1  2  2  1  0 -1 -1 -1  0  1  2  2  1]

The input vector consists of integers, not necessarily only 1 and -1, both positive and negative. Assume that upper_lim >= lower_lim. If the first element of the vector is outside the boundary, jump directly to the boundary (see last example).

Write a function that takes a vector of integers as input, and two integers that represent the upper and lower limits. Output the bounded cumulative vector, as defined above. The input can be as either function arguments or from STDIN.

Standard code golf rules apply.

Examples:

upper_lim = 6
lower_lim = -2
vec =     [1  4  3 -10  3  2  2  5 -4]
cum_vec = [1  5  6  -2  1  3  5  6  2]

upper_lim = 100
lower_lim = -100
vec =     [1  1  1  1  1  1]
cum_vec = [1  2  3  4  5  6]

upper_lim = 5
lower_lim = 0
vec =     [10 -4 -3  2]
cum_vec = [5   1  0  2]

upper_lim = 0
lower_lim = 0
vec =     [3  5 -2  1]
cum_vec = [0  0  0  0]

upper_lim = 10
lower_lim = 5
vec =     [1  4  6]
cum_vec = [5  9 10]
           |
           Note, jumped to 5, because 5 is the lower bound.
\$\endgroup\$

11 Answers 11

5
\$\begingroup\$

Pyth, 14 bytes

t.u@S+Q+NY1vwZ

Try it online: Demonstration or Test Suite

Explanation

t.u@S+Q+NY1vwZ  implicit: Q = first input list [upper_lim, lower_lim]
 .u        vwZ  for each number Y in the next input list, update N = 0 with:
       +NY         N + Y
     +Q            append this to Q
    S              sort this list
   @      1        take the middle element
                .u returns a list with all intermediate values of N
t                  remove the first value, print the rest
\$\endgroup\$
5
\$\begingroup\$

CJam, 16 15 bytes

l~f{\T++$1=:T}`

Try it online

This takes the list as first argument, and the pair of upper/lower limit as a second 2-element list. Example input:

[1 4 3 -10 3 2 2 5 -4] [6 -2]

The latest version saves 1 byte by sorting the 3 values, and taking the middle value, instead of using a max and min operation. This was also used in Jakube's solution, as well as suggested by Martin.

Explanation:

l~    Get and parse input. This leaves the value and bounds lists on the stack.
f{    Apply block with value (the bounds list).
  \     Swap new value to top.
  T     Get previous value from variable T (which is default initialized to 0).
  +     Add new value and previous value.
  +     Append new value to bounds list, producing a 3 value list.
  $     Sort it...
  1=    And take the middle value.
  :T    Store in variable T for next iteration.
}     End of apply loop.
`     Convert list to string.
\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 43 bytes

(l,u,v,p=0)=>v.map(c=>p=(p+=c)<l?l:p>u?u:p)

Defines an anonymous function that takes input in the format lower bound, upper bound, vector (as JS Array). I don't know if it could be any shorter, but I'll try. Suggestions welcome!

\$\endgroup\$
4
\$\begingroup\$

Haskell, 37 bytes

u#l=tail.scanl(((min u.max l).).(+))0

Usage example: 6 # (-2) $ [1,4,3,-10,3,2,2,5,-4] -> [1,5,6,-2,1,3,5,6,2].

Start the sum with 0 to fix initial values out of bounds. Take the tail to remove it from the final result.

\$\endgroup\$
3
\$\begingroup\$

R, 61 bytes

function(x,l,u,s=0)sapply(x,function(i)s<<-min(u,max(l,s+i)))

sapply is the function to apply a function to every element of a vector (here x) but it is usually done in a context where all the evaluations are independent and without side-effect. Here, however, I use the <<- operator to make an assignment in the parent/calling environment of sapply so that the cumulative sum s can be stored outside the iterative evaluations. This is very bad practice...

\$\endgroup\$
3
\$\begingroup\$

Mathematica, 46 bytes

Rest@FoldList[{a,b}Min[a+b,#2]~Max~#3,0,#]&

The funny character is U+F4A1 for \[Function]. If the first element can be assumed to be in the range, I could save 7 bytes.

\$\endgroup\$
3
\$\begingroup\$

Julia, 44 42 38 bytes

f(x,l,u,s=0)=[s=clamp(s+i,l,u)for i=x]

This creates a function f that accepts an array and two integers and returns an array.

Ungolfed:

function f(v::Array, u::Int, l::Int, s::Int = 0)
    # The parameter s is the cumulative sum, which begins
    # at 0

    # For each element i of v, define s to be s+i if
    # l ≤ s+i ≤ u, l if s+i < l, or u if s+i > u
    x = [s = clamp(s + i, l, u) for i = v]

    return x
end

Saved 2 bytes by using ETHproductions' idea of including the cumulative sum as a function parameter and 1 bytes thanks to Glen O.

\$\endgroup\$
3
\$\begingroup\$

Python 2, 67 Bytes

lambda u,l,v:reduce(lambda x,y:x+[max(min(x[-1]+y,u),l)],v,[0])[1:]
\$\endgroup\$
2
\$\begingroup\$

Minkolang 0.9, 30 bytes

0I3-[2g+d0c`,3&x0cd1c`3&x1cdN]

This, as a function, assumes the stack has been pre-initialized to high, low, vector. The full program is below (37 bytes) and takes input as high, low, vector.

(n$I$)0I4-[2g+d0c`,3&x0cd1c`3&x1cdN].

Try it here.

Explanation

(n$I$)                                   Read in integers from input until empty
      0                                  Initialize cumulative sum
       I4-[                        ]     Loop over vector
           2g+                           Get the next partial sum
              d0c`,3&x0c                 If too high, replace with high
                        d1c`3&x1cd       If too low, replace with low
                                  N      Output as integer
                                    .    Stop
\$\endgroup\$
1
\$\begingroup\$

C 98 bytes

It's long, but it works

#define P printf(
void c(*v,n,u,l,s,c){P"[");while(c++<n)s+=*v++,s=s<u?s>l?s:l:u,P"%d ",s);P"]");}

Usage example

#define P printf(
void c(*v,n,u,l,s,c) {
    P"[");
    while(c++<n)
        s+=*v++,s=s<u?s>l?s:l:u,P"%d ",s);
    P"]");
}

int main() {
    int vec[9] = {1, 4, 3, -10, 3, 2, 2, 5, -4};
    int upper = 6, lower = -2, count = 9;
    c(vec, count, upper, lower, 0, 0);
}

The output would be

[1 5 6 -2 1 3 5 6 2 ]
\$\endgroup\$
1
\$\begingroup\$

APL, 29 27 18 bytes

As Dennis pointed out in chat, \ (expand) works from left to right, but applies the function being expanded with from right to left. So we can't just do 1↓(⎕⌈⎕⌊+)\0,⎕. We work around this by taking the ,\ of the array, and then processing each subarray separately using / (fold).

1↓(⎕⌈⎕⌊+)/¨⌽¨,\0,⎕

Input in the order array, upper bound, lower bound.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.