首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Haskell -最频繁的值

Haskell -最频繁的值
EN

Stack Overflow用户
提问于 2012-12-12 12:51:37
回答 4查看 4.1K关注 0票数 5

如何获取列表示例中最常用的值:

代码语言:javascript
运行
复制
[1,3,4,5,6,6] -> output 6
[1,3,1,5] -> output 1

我正在尝试通过我自己的函数来获得它,但我无法实现它,你们能帮助我吗?

我的代码:

代码语言:javascript
运行
复制
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))
EN

回答 4

Stack Overflow用户

发布于 2012-12-12 19:44:25

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

代码语言:javascript
运行
复制
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表示一个“真正的”返回值。例如:

代码语言:javascript
运行
复制
mostCommon :: Ord a => [a] -> Maybe a
mostCommon [] = Nothing
mostCommon list = Just ... -- your implementation here

这要好得多,因为从代码安全的角度来看,部分函数(对于某些输入值未定义的函数)是可怕的。您可以使用模式匹配(在NothingJust x上匹配)和Data.Maybe中的函数(最好是fromMaybemaybe,而不是fromJust)来操作Maybe的值。

票数 7
EN

Stack Overflow用户

发布于 2012-12-12 14:11:26

如果您想从代码中获得一些想法,可以实现您希望实现的目标,下面是一个示例:

代码语言:javascript
运行
复制
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)]
票数 6
EN

Stack Overflow用户

发布于 2012-12-12 14:07:09

以下是一些建议

del可以使用filter实现,而不是编写自己的递归。在你的定义中有一个错误,你在删除时需要给ys而不是y

代码语言:javascript
运行
复制
del x = filter (/=x)

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

代码语言:javascript
运行
复制
obj  x = filter (==x)

tam只是一个length函数

代码语言:javascript
运行
复制
-- tam = length

你不需要为n1n保留一个列表。我还使您的代码更具可读性,尽管我没有对您的算法进行任何更改。

代码语言:javascript
运行
复制
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)

另一种不是很理想但可读性更好的方法是

代码语言:javascript
运行
复制
import Data.List
import Data.Ord

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

我将尝试简单地解释一下这段代码是做什么的。您需要找到列表中最频繁的元素,因此首先要想到的是找到所有元素的频率。现在group是一个组合了相邻相似元素的函数。

代码语言:javascript
运行
复制
> group [1,2,2,3,3,3,1,2,4]
[[1],[2,2],[3,3,3],[1],[2],[4]]

所以我使用排序将相同的相邻元素放在一起

代码语言:javascript
运行
复制
> 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,您可以使用它根据给定的比较函数进行排序。所以基本上我已经对子列表的length进行了排序(翻转只是为了使排序降序而不是升序)。

代码语言:javascript
运行
复制
> sortBy (flip $ comparing length) . group . sort $ [1,2,2,3,3,3,1,2,4]
[[2,2,2],[3,3,3],[1,1],[4]]

现在,您只需执行两次head即可获得频率最高的元素。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13833017

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档