How to neatly get the sum of symmetric elements in a list?
This is a simple though somewhat wasteful solution:
symmSum[l_List] := Take[l + Reverse[l], Ceiling[Length[l]/2]]
It will give you the middle element twice, not once. Is it important that you only get c
(and not 2c
) when applying this function to {a,b,c,d,e}
? That's easy to do (avoiding computing elements twice is also easy), but will make the function slightly longer. These solutions all use Length
though.
Here's a pattern-based solution which avoids Length
:
iter[{result___}, {s_, mid___, e_}] := iter[{result, e + s}, {mid}]
iter[{result___}, {}] := {result}
iter[{result___}, {mid_}] := {result, mid}
symmSum[l_List] := iter[{}, l]
You may want to modify this as
symmSum[l_List] := Block[{$IterationLimit = Infinity}, iter[{}, l]]
to make it work for arbitrarily long lists.
Playing with patterns:
{a, b, c, d, e} //. {h_, b___, t : Except[_List]} :> {h + t, {b}} // Flatten
This can be written more efficiently, without the full rescanning inherent in //.
, using recursion:
f1 = # /. {h_, b___, t_} :> Prepend[f1 @ {b}, h + t] &;
Also as a DownValues definition which is a bit more efficient still:
f2[{h_, b___, t_}] := Prepend[f2 @ {b}, h + t]
f2[x_] := x
f2 @ {a, b, c, d, e}
f2 @ {a, b, c, d, e, f}
{a + e, b + d, c} {a + f, b + e, c + d}
Disregarding elegance, this is the fastest method I could come up with for packed arrays:
Module[{ln = Length@#, x},
x = #[[ ;; ⌈ln/2`⌉ ]];
x += #[[ -1 ;; ⌊ln/2`⌋ + 1 ;; -1 ]];
If[OddQ @ ln, x[[-1]] /= 2 ];
x
] &
I imagine it can be bested by compile-to-C in v8, but I don't have that.
What's wrong with Length
? It's a very efficient function to callculate (since lists are vectors internally, i.e. arrays of fixed size, whose length is precisely known to the program at all times).
symSum = Module[{result, length = Length[#]},
result = (# + Reverse@#) [[1 ;; Ceiling[length/2]]];
If[OddQ[length], result[[-1]] /= 2];
result
] &;
symSum@{a, b, c, d, e, f}
symSum@{a, b, c, d, e}
{a + f, b + e, c + d} {a + e, b + d, c}