Using reduce() with tuples created by zip()
Craig Dillabaugh
cdillaba at cg.scs.carleton.ca
Fri Nov 1 07:22:56 PDT 2013
On Friday, 1 November 2013 at 09:31:41 UTC, Philippe Sigaud wrote:
> On Thu, Oct 31, 2013 at 8:59 PM, Craig Dillabaugh <
> cdillaba at cg.scs.carleton.ca> wrote:
>
>>
>>>>
>> Thanks, I will try both your, and Bearophile's ideas and see
>> if I
>> can figure out how they work.
>
>
>
> reduce takes a range and eagerly (that is, not lazily) builds a
> value from
> it. In your case, it builds the squared distance between two
> points. The
> returned value can be anything: a numerical value, but also
> another range,
> a complex object, an so on. As long as it can be built
> increasingly,
> you're good.
>
> Given a range [a,b,c,..., z] and a binary function f,
> reduce!(f)([a,b,c,...]) calculates f(a,b), then f(f(a,b), c),
> up to f(...
> f( f( f(a,b),c), d), ...,z).
>
> The only question is whether you give it a seed value, or if it
> takes the
> first range element as seed (f(seed, a), f(f(seed,a),b) and
> son on).
> std.algorithm.reduce provides both overloads.
>
> Note the only thing you get is the final result, not the
> internal f(f(...'s
> applications.
>
> If you want a sum:
>
> reduce!( (result,elem) => result + elem )(range)
>
> or
>
> reduce!( (result,elem) => result + elem )(range, 0)
>
> Sum of squares:
>
> reduce!( (result, elem) => result + elem^^2 )(range, 0)
>
> In your case, the basic element is a tuple, coming from zip.
> Access to the
> two elements is done with [0] or [1]. So:
>
> reduce!( (result, elem) => result + (elem[0]-elem[1])^^2
> )(zippedRange, 0)
This is really where my problem arose. I understood everything up
to here, but I sort of had this idea, "hey zip returns a tuple so
that somehow the compiler
was going to figure out for me that function(e) has two values"
and is thus
a binary function so this should work (the 0.0 on the end was my
start value):
reduce!(function(e) { return (e[1]-e[0])*(e[1]-e[0]); })(0.0)
However, of course the compiler see's the tuple as just one value
- which is where I made my mistake.
>
> Of course, it would be easy to write a small n-range reduce
> helper
> function, that takes n ranges and reduces them in parallel:
>
> reduce!( (result, a, b) => result + (a-b)^^2 )(rangeA, rangeB,
> 0)
>
> Note that reduce is a versatile function: you can duplicate
> filter and map
> functionalities with it. The only thing to remember is that,
> compared to
> other iteration algorithm/ranges, it's eager. Don't use it on
> an infinite
> range!
>
>
> We could also have a slightly different version that lazily
> produces the
> intermediate results as a range. IIRC, it's called 'scan' in
> Haskell. It's
> sometimes interesting to have it: you can interrupt the ongoing
> calculation
> when the result is 'good enough', not waiting for the entire
> input range to
> be consumed.
More information about the Digitalmars-d-learn
mailing list