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, <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
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 <max.rabkin@gmail.com>:
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, <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
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