过滤双打列表并将函数应用于该结果

时间:2016-11-03 14:15:28

标签: haskell

[92.0,81.0,81.0,41.0,69.0,95.0,82.0,25.0,92.0,18.0,60.0,68.0,29.0,75.0,87.0,24.0,99.0,93.0,76.0,49.0,36.0]

测试列表在

之上

基本上我给了一个数字列表,我要提取三个组,然后应用一个函数来得到我的答案。我不能使用导入或递归。

“获取双打列表,将每个连续的三个双打组视为三角形三边的长度,使用triangle_area计算其面积;并且在处理列表中的所有双打后,将所有计算的区域返回为双打名单。“

triangle_area :: Double -> Double -> Double -> Double
triangle_area a b c = sqrt (s * (s - a) * (s - b) * (s - c)) where s = (a +           b + c) / 2.0

triangle_areas :: [Double] -> [Double]
triangle_areas xs = []

我打算在该列表上使用过滤器,但不能使用双打。在给定列表中,三个集合表示triangle_area函数的(a,b,c)。然后我需要将triangle_area函数应用于这些数字。

不确定如何做到这一点

所以给出[92.0,81.0,81.0,41.0,69.0,95.0,82.0,25.0,92.0,18.0,60.0,68.0,29.0,75.0,87.0,24.0,99.0,93.0,76.0,49.0,36.0]

上面列表之后的区域应该是 [3066.9,1258.5,986.4,510.9,1052.0,1106.7,712.6]

这是另一种尝试 但它不起作用

triangle_area :: Double -> Double -> Double -> Double
triangle_area a b c = sqrt (s * (s - a) * (s - b) * (s - c)) where s = (a +     b + c) / 2.0

splitEvery :: Int -> [a] -> [[a]]
splitEvery n = takeWhile (not.null) . map (take n) . iterate (drop n)

triangle_areas :: [Double] -> [Double]
triangle_areas [] = []
triangle_areas (a:b:c:xs) = triangle_area a b c : triangle_areas xs

基本上我想做splitEvery 3 [1..9],然后在那些分解列表中使用triangle_area。

triangle_areas 目前效果很好,但我无法使用递归,所以我需要返工。

WORKING

splitEvery :: Int -> [a] -> [[a]]
splitEvery n = takeWhile (not.null) . map (take n) . iterate (drop n)

triangle_area [a,b,c] = sqrt (s * (s - a) * (s - b) * (s - c)) 
                    where s = (a + b + c) / 2.0

triangle_areas = map triangle_area . splitEvery 3

非常感谢切普纳

2 个答案:

答案 0 :(得分:3)

您可以使用map的定义来获取灵感。

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

map将其函数应用于一个参数;你想将你的函数应用于三个参数。

triangle_areas :: [Double] -> [Double]
triangle_areas xs = map3 triangle_area xs
                    where map3 f (s1:s2:s3:rest) = f s1 s2 s3 : map3 f rest
                          -- map3 _ [s1, s2] = ???
                          -- map3 _ [s1] = ???
                          map3 _ [] = []

我将map3作为部分函数,​​对于剩下1或2个值的列表,它是未定义的。

您的splitEvery没问题;您只需要修改triangle_area的定义,以便它可以将3元素列表作为输入。

triangle_area [a,b,c] = sqrt (s * (s - a) * (s - b) * (s - c)) 
                        where s = (a + b + c) / 2.0

现在,您可以将其映射到splitEvery的输出。

triangle_areas = map triangle_area . splitEvery 3

答案 1 :(得分:0)

以下不是最优雅的,但可以作为灵感(至少它适用于你的例子):


    triangle_areas :: [Double] -> [Double]
    triangle_areas =
      fst .
      foldl (\(r, sides) x ->
              if length sides == 2
              then (r ++ [triangle_area (sides !! 0) (sides !! 1) x], [])
              else (r, sides ++ [x]))
      ([],[])

它的工作原理是累积计算出的面积和当前三角形的边,其面积将在下一个计算。这是在元组(r, sides)中完成的。当我们得到三角形的三个边(在列表sides中累积2个,在参数x中累积第三个)时,我们 计算区域并将其添加到结果列表中,否则我们保持结果列表不变并将当前侧(参数x)添加到sides