Mapping over multiple values of a list at once?

Hi, Imagine you have a list with n-values. You are asked to iterate over the list and calculate the average value of each 3 neighbouring values. For example, starting from [4,3,2,6,7] you need to find the averages of 4,3,2 and 3,2,6 and 2,6,7 resulting in [3,4,5] What is the most elegant way to do that? The naive ansatz to use "(!!") excessively sounds pretty inefficient. Bye, Lenny

transpose & tails, I guess. haskell@kudling.de wrote:
Hi,
Imagine you have a list with n-values. You are asked to iterate over the list and calculate the average value of each 3 neighbouring values.
For example, starting from
[4,3,2,6,7]
you need to find the averages of
4,3,2 and 3,2,6 and 2,6,7
resulting in
[3,4,5]
What is the most elegant way to do that? The naive ansatz to use "(!!") excessively sounds pretty inefficient.
Bye, Lenny _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

My first approach would be to generate the list of sliding windows: [[4,3,2],[3,2,6],[2,6,7]] after importing Data.List:
map (take 3) . tails $ [4,3,2,6,7] [[4,3,2],[3,2,6],[2,6,7],[6,7],[7],[]]
Not quite what we want, but close:
filter ((== 3) . length) . map (take 3) . tails $ [4,3,2,6,7] [[4,3,2],[3,2,6],[2,6,7]]
So (filter ((== 3) . length) . map (take 3) . tails) seems to be the
desired function. Now just map average.
However, we don't really need the sliding windows themselves, just the
sliding sum. There might be a slightly more efficient way to do that,
but I'll leave it as an exercise for you or somebody else.
--Max
On Thu, Aug 27, 2009 at 10:19 AM,
Hi,
Imagine you have a list with n-values. You are asked to iterate over the list and calculate the average value of each 3 neighbouring values.
For example, starting from
[4,3,2,6,7]
you need to find the averages of
4,3,2 and 3,2,6 and 2,6,7
resulting in
[3,4,5]
What is the most elegant way to do that? The naive ansatz to use "(!!") excessively sounds pretty inefficient.
Bye, Lenny _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hi Max
How about a paramorphism?
slideAvg3 :: [Int] -> [Int]
slideAvg3 = para phi [] where
phi x ((y:z:_),acc) = average3 x y z : acc
phi x (_,acc) = acc
-- helpers
-- paramorphism (generalizes catamorphism (fold))
para :: (a -> ([a], b) -> b) -> b -> [a] -> b
para phi b [] = b
para phi b (x:xs) = phi x (xs, para phi b xs)
average3 :: Int -> Int -> Int -> Int
average3 a b c = round $ (fromIntegral $ a+b+c)/3
I haven't tested for efficiency though.
Best wishes
Stephen
2009/8/27 Max Rabkin
However, we don't really need the sliding windows themselves, just the sliding sum. There might be a slightly more efficient way to do that, but I'll leave it as an exercise for you or somebody else.
--Max

Just wondering, what should be the expected output be of something
like mavg 4 [1..3]? [3%2] or []?
Patai's and Eugene's solutions assume the former.
On Thu, Aug 27, 2009 at 10:19 AM,
Hi,
Imagine you have a list with n-values. You are asked to iterate over the list and calculate the average value of each 3 neighbouring values.
For example, starting from
[4,3,2,6,7]
you need to find the averages of
4,3,2 and 3,2,6 and 2,6,7
resulting in
[3,4,5]
What is the most elegant way to do that? The naive ansatz to use "(!!") excessively sounds pretty inefficient.
Bye, Lenny _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

haskell@kudling.de wrote:
You are asked to iterate over the list and calculate the average value of each 3 neighbouring values.
Lambda Fu, form 72 - three way dragon zip averages3 xs = zipWith3 avg xs (drop 1 xs) (drop 2 xs) where avg a b c = (a+b+c) / 3 Regards, apfelmus -- http://apfelmus.nfshost.com
participants (8)
-
haskell@kudling.de
-
Heinrich Apfelmus
-
Jon Fairbairn
-
Martijn van Steenbergen
-
Max Rabkin
-
Miguel Mitrofanov
-
Raynor Vliegendhart
-
Stephen Tetley