Haskell - 最常见的价值

时间:2012-12-12 04:51:37

标签: haskell recursion functional-programming

如何在列表示例中获得最常见的值:

[1,3,4,5,6,6] -> output 6
[1,3,1,5] -> output 1

我试图通过我自己的功能得到它,但我无法实现它,你们可以帮助我吗?

我的代码:

del x [] = []
del x (y:ys) = if x /= y 
            then y:del x y 
            else del x ys



obj  x []= []
obj  x (y:ys) = if x== y then y:obj x y else(obj  x ys)

tam [] = 0
tam (x:y) = 1+tam  y

fun (n1:[]) (n:[]) [] =n1
fun (n1:[]) (n:[]) (x:s) =if (tam(obj x (x:s)))>n then fun (x:[]) ((tam(obj x (x:s))):[]) (del x (x:s)) else(fun (n1:[]) (n:[]) (del x (x:s))) 

rep (x:s) = fun  (x:[]) ((tam(obj x (x:s))):[]) (del x (x:s))

4 个答案:

答案 0 :(得分:7)

扩展Satvik的最后一个建议,您可以使用(&&&) :: (b -> c) -> (b -> c') -> (b -> (c, c'))中的Control.Arrow(请注意,为了简单起见,我在该类型签名中替换了a = (->))以干净地执行decorate-sort-undecorate transform

mostCommon list = fst . maximumBy (compare `on` snd) $ elemCount
      where elemCount = map (head &&& length) . group . sort $ list

head &&& length函数的类型为[b] -> (b, Int)。它将列表转换为其第一个元素及其长度的元组,因此当它与group . sort组合时,您将获得列表中每个不同值的列表及其发生的次数。


此外,您应该考虑在致电mostCommon []时会发生什么。显然没有合理的价值,因为根本没有元素。就目前而言,所提出的所有解决方案(包括我的)都只是在一个空列表中失败,这不是好的Haskell。正常的做法是返回Maybe a,其中Nothing表示错误(在本例中为空列表),Just a表示“实际”返回值。 e.g。

mostCommon :: Ord a => [a] -> Maybe a
mostCommon [] = Nothing
mostCommon list = Just ... -- your implementation here

这更好,因为从代码安全的角度来看,部分函数(某些输入值未定义的函数)非常糟糕。您可以使用模式匹配(MaybeNothing上的匹配)和Data.Maybe中的函数(最好是Just xfromMaybe来操纵maybe值比fromJust)。

答案 1 :(得分:6)

如果您希望从代码中获得一些您希望实现的想法,请举例说明:

import Data.List (nub, maximumBy)
import Data.Function (on)

mostCommonElem list = fst $ maximumBy (compare `on` snd) elemCounts where
    elemCounts = nub [(element, count) | element <- list, let count = length (filter (==element) list)]

答案 2 :(得分:3)

以下是一些建议

del可以使用过滤器实现,而不是编写自己的递归。在您的定义中出现了错误,您需要在删除时提供ys而不是y

del x = filter (/=x)

obj类似于具有不同过滤功能的del。同样,在您的定义中,您需要在ys中提供y而不是obj

obj  x = filter (==x)

tam只是length函数

-- tam = length

您无需保留n1n的列表。虽然我没有对您的算法进行任何更改,但我还是使您的代码更具可读性。

fun n1 n [] =n1
fun n1 n xs@(x:s) | length (obj x xs) > n = fun x (length $ obj x xs) (del x xs)
                  | otherwise             = fun n1 n $ del x xs

rep xs@(x:s) = fun  x (length $ obj x xs) (del x xs)

另一种方式,不是非常优化,但更具可读性

import Data.List
import Data.Ord

rep :: Ord a => [a] -> a
rep = head . head . sortBy (flip $ comparing length) . group . sort

我将尝试简要解释这段代码的用途。您需要找到列表中最常见的元素,因此应该首先想到的是找到所有元素的频率。现在group是一个组合相邻相似元素的函数。

> group [1,2,2,3,3,3,1,2,4]
[[1],[2,2],[3,3,3],[1],[2],[4]]

所以我使用sort来将彼此相邻的元素放在一起

> sort [1,2,2,3,3,3,1,2,4]
[1,1,2,2,2,3,3,3,4]

> group . sort $ [1,2,2,3,3,3,1,2,4]
[[1,1],[2,2,2],[3,3,3],[4]]

查找具有最大频率的元素只会减少以找到具有最大元素数量的子列表。这里有函数sortBy,您可以根据给定的比较函数对其进行排序。所以基本上我已经对{1}}的子列表进行了排序(翻转只是为了使排序降序而不是升序)。

length

现在你可以两次> sortBy (flip $ comparing length) . group . sort $ [1,2,2,3,3,3,1,2,4] [[2,2,2],[3,3,3],[1,1],[4]] 来获得频率最高的元素。

答案 3 :(得分:0)

假设您已经拥有argmax功能。你可以写 你自己甚至更好,你可以重用list-extras包。我强烈建议你 无论如何要看看包装。

然后,这很容易:

import Data.List.Extras.Argmax ( argmax )

-- >> mostFrequent [3,1,2,3,2,3]
-- 3
mostFrequent xs = argmax f xs
  where f x = length $ filter (==x) xs