如何在Haskell中返回中间数字

时间:2011-05-24 20:42:20

标签: haskell int guard

我有一个函数的开头,我不确定如何返回中间数(即既不是最大也不是最小的数字):

middleNumber :: Int -> Int -> Int -> Int
middleNumber a b c
    | ...

6 个答案:

答案 0 :(得分:4)

我建议你将功能分为两个步骤:首先,对三个数字进行排序。然后,采取中间元素。第一步,还要考虑你是否可以一步一步;每一步都使它更接近于完全排序,然后尾部递归以使其更接近。

答案 1 :(得分:3)

强制性的Rube-Goldberg回答:

import Control.Applicative

middleNumber a b c = sum $ [sum, negate.minimum, negate.maximum] <*> [[a,b,c]]

<强> [编辑]

这是另一个版本:

middleNumber a b c = fst $ maximumBy (compare `on` abs.snd) [(a,b-c),(b,c-a),(c,a-b)] 

我确信我们可以将此转换为箭头语法以进行进一步的混淆,但我将该任务留给感兴趣的读者。

答案 2 :(得分:2)

“中间数字”大于其中一个数字,但小于另一个数字。并且只有一个中间数字。解决这个问题最机械的方法是开始

middleNumber a b c
    | a < b && a > c = a

检查a是否为中间数,小于b但大于c

现在假设a是中间号码,但实际上更多b更少而不是c怎么办?还有另一名警卫。如果b是中间数,该怎么办?还有另外2名警卫。如果c是中间数,该怎么办?共有6个不同的案例,还有2个警卫。

(顺便说一句,表达式| a < b && a > c = a被称为守卫。如果你还没有牢牢掌握什么是守卫,那么我建议LYAH # Guards

当然,有更好的方法来编写函数,但出于理解的目的,能够手动和系统地分解所有可能的情况并确定在每种情况下要做什么都是很好的。 How To Design Programs是一本很好的书,用于学习如何以这种方式系统化。

答案 3 :(得分:1)

扩展 Dan Burton 对警卫的回答,我在各自的警卫中评估了 a、b、c 案例。但是,当两个数字相等时会发生什么?那么中间的数字应该是重复的数字之一。

middleNumber :: Int -> Int -> Int -> Int
middleNumber a b c
    | (a > b && a < c) || (a > c && a < b) = a
    | (b > a && b < c) || (b > c && b < a) = b
    | (c > a && c < b) || (c > b && c < a) = c
    | otherwise = if a == b then a else c

答案 4 :(得分:0)

我做了一个快速的暴力方法,但这肯定不是最好的解决方案

import Data.List
middleNum :: Int -> Int -> Int -> Int
middleNum a b c = (\[_,m,_] -> m) $ sort $ a:b:c:[]

显然这是一个非常糟糕的主意,因为它明确依赖于列表中有3个项目,但是它完成了工作

答案 5 :(得分:0)

您可以利用守卫和 where 以简单的方式获得相同的结果:

middleNumber :: Int -> Int -> Int -> Int
middleNumber x y z
  | a == x = max y z
  | a == y = max x z
  | a == z = max x y
  where
    a = max x $ max y z

如果您无权访问内置的 max。您可以轻松编写自己的。

max' :: Int -> Int -> Int
max' x y
  | x > y = x
  | otherwise = y