<div dir="ltr">Ah, that's nice, I didn't know that itertools.accumulate now has an optional "func" parameter.  Although to get the exact same behaviour (output the same length as input) you'd actually have to do:<div><br></div><div>   <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">smooth_signal = itertools.islice(itertools.accumulate([initial_average] + signal, compute_avg), 1, None)</span></div><div><br></div><div>And you'd also have to use iterools.chain to concatenate the initial_average to the rest if "signal" were a generator instead of a list, so the fully general version would be:</div><div><br></div><div>    <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">smooth_signal = itertools.islice(itertools.accumulate(itertools.chain([initial_average], signal), compute_avg), 1, None)</span></div><div><div><br></div><div>I find this a bit awkward, and maintain that it would be nice to have this as a built-in language construct to do this natively.  You have to admit: </div><div><br></div><div>    smooth_signal = [average = (1-decay)*average + decay*x for x in signal from average=0.]<br></div><div><br></div><div>Is a lot cleaner and more intuitive than:</div><div><br></div><div><div>    dev compute_avg(avg, x):</div><div>        return (1 - decay)*avg + decay * x</div><div><br></div><div>    <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">smooth_signal = itertools.islice(itertools.accumulate(itertools.chain([initial_average], signal), compute_avg), 1, None)</span></div></div><div><br></div><div>Moreover, if added with the "last" builtin proposed in the link, it could also kill the need for reduce, as you could instead use:</div><div><br></div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">    last_smooth_signal = last(average = (1-decay)*average + decay*x for x in signal from average=0.)</span><br></div><div><br></div><div><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Apr 5, 2018 at 1:48 PM, Clint Hepner <span dir="ltr"><<a href="mailto:clint.hepner@gmail.com" target="_blank">clint.hepner@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
> On 2018 Apr 5 , at 12:52 p, Peter O'Connor <<a href="mailto:peter.ed.oconnor@gmail.com">peter.ed.oconnor@gmail.com</a>> wrote:<br>
><br>
> Dear all,<br>
><br>
> In Python, I often find myself building lists where each element depends on the last.  This generally means making a for-loop, create an initial list, and appending to it in the loop, or creating a generator-function.  Both of these feel more verbose than necessary.<br>
><br>
> I was thinking it would be nice to be able to encapsulate this common type of operation into a more compact comprehension.<br>
><br>
> I propose a new "Reduce-Map" comprehension that allows us to write:<br>
> signal = [math.sin(i*0.01) + random.normalvariate(0, 0.1) for i in range(1000)]<br>
> smooth_signal = [average = (1-decay)*average + decay*x for x in signal from average=0.]<br>
> Instead of:<br>
> def exponential_moving_average(<wbr>signal: Iterable[float], decay: float, initial_value: float=0.):<br>
>     average = initial_value<br>
>     for xt in signal:<br>
>         average = (1-decay)*average + decay*xt<br>
>         yield average<br>
><br>
> signal = [math.sin(i*0.01) + random.normalvariate(0, 0.1) for i in range(1000)]<br>
> smooth_signal = list(exponential_moving_<wbr>average(signal, decay=0.05))<br>
> I've created a complete proposal at: <a href="https://github.com/petered/peps/blob/master/pep-9999.rst" rel="noreferrer" target="_blank">https://github.com/petered/<wbr>peps/blob/master/pep-9999.rst</a> , (and a pull-request) and I'd be interested to hear what people think of this idea.<br>
><br>
> Combined with the new "last" builtin discussed in the proposal, this would allow u to replace "reduce" with a more Pythonic comprehension-style syntax.<br>
<br>
<br>
</span>See itertools.accumulate, comparing the rough implementation in the docs to your exponential_moving_average function:<br>
<br>
    signal = [math.sin(i*0.01) + random.normalvariate(0,0.1) for i in range(1000)]<br>
<br>
    dev compute_avg(avg, x):<br>
        return (1 - decay)*avg + decay * x<br>
<br>
    smooth_signal = accumulate([initial_average] + signal, compute_avg)<br>
<br>
--<br>
Clint</blockquote></div><br></div>