Selecting a quantity from a list I want to implement a function take_upto_n(A, n)
such that for e.g.
take_upto_n([1,2,3,4], 8) returns [1,2,3,2]
take_upto_n([1,2,4,3], 8) returns [1,2,4,1]
take_upto_n([1,2,3,4], 100) returns [1,2,3,4]
take_upto_n([1,2,3,4], 3) returns [1,2,0,0]

Assume A contains non-negative values only. n is also non-negative
This is straightforward with a loop
def take_upto_n(A, n):
    out = []
    for x in A:
        out += [min(n, x)]
        n -= min(n, x)
    return out

We can also do this with numpy, but this I.M.O. is fairly unreadable:
def take_upto_n(A, n):
    A = np.array(A)
    return np.clip(n + A - np.cumsum(A), 0, A)

Is there some standard function that does this - couldn't find it myself (or didn't know how to search)?
If there isn't any such function, any advice on how to make it not look like &quot;what is this?&quot; (the n + A - np.cumsum(A) is the real killer)?
Your regular Python implementation generally looks reasonable, and unless numpy
offers a performance boost that you really need, I would not recommend it for
this use case: the brevity/clarity tradeoff seems bad.
My biggest suggestion is to consider clearer names. A function with signature
of take_upto_n(A, n) makes me think the function takes an iterable and
returns a sequence of n values. Something like take_upto_sum(A, total)
seems more communicative to me. And even &quot;take&quot; isn't quite right: take
implies a filtering process (we'll take some and leave some). But we
are limiting or capping. Perhaps you can think of something even better.
This example presents a classic Python dilemma: you want to do a simple map
over a list to generate a new list, so of course you would like to knock it out
in a comprehension or something equally cool. But while iterating,
you also need to modify some other variable to keep track of state, and Python
mostly lacks the assignments-as-expression idiom that allows such trickery in
other languages (for example, old-school Perl map/grep one-liners and their
ilk). If you are using a sufficiently modern Python, you can use the walrus
operator to compress the code a bit, but it doesn't get you all the way there.
Honestly, I wouldn't even bother with the walrus (but I would assign min() to
a convenience variable to avoid repetition and thus help readability). In any
case, the walrus approach:
def take_upto_sum(A, total):
    out = []
    for x in A:
        out.append(y := min(total, x))
        total -= y
    return out

I suppose it is possible to express this as a single list comprehension if we
take advantage of the built-in itertools and operator modules. Like the
numpy solution, this approach reminds me of the Spinal Tap quote: It's such a
fine line between stupid, and uh ... clever.
from itertools import accumulate
from operator import sub

def take_upto_sum(A, total):
    return [
        max(min(x, acc), 0)
        for x, acc in zip(A, accumulate(A, sub, initial=total))
    ]