问题是计算排序的整数列表的模式(最常出现的值)。
[1,1,1,1,2,2,3,3] -> 1
[2,2,3,3,3,3,4,4,8,8,8,8] -> 3 or 8
[3,3,3,3,4,4,5,5,6,6] -> 3
只需使用Prelude库。
Prelude库中的函数filter,map,foldr?
答案 0 :(得分:5)
从头开始。
您想要通过序列并获得整数的最大频率。
这听起来像是折叠的工作,因为折叠在给出最终结果之前会经历一个聚合值的序列。
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl的类型如上所示。我们已经可以填写一些(我发现这可以帮助我找出我需要的类型)
foldl :: (a -> Int -> a) -> a -> [Int] -> a
我们需要通过折叠来获得价值。我们必须跟踪当前运行和当前计数
data BestRun = BestRun {
currentNum :: Int,
occurrences :: Int,
bestNum :: Int,
bestOccurrences :: Int
}
所以现在我们可以填写更多内容:
foldl :: (BestRun -> Int -> BestRun) -> BestRun -> [Int] -> BestRun
所以我们想要一个执行聚合的函数
f :: BestRun -> Int -> BestRun
f (BestRun current occ best bestOcc) x
| x == current = (BestRun current (occ + 1) best bestOcc) -- continuing current sequence
| occ > bestOcc = (BestRun x 1 current occ) -- a new best sequence
| otherwise = (BestRun x 1 best bestOcc) -- new sequence
现在我们可以使用foldl
作为
bestRun :: [Int] -> Int
bestRun xs = bestNum (foldl f (BestRun 0 0 0 0) xs)
答案 1 :(得分:5)
Prelude库中的函数filter,map,foldr?
停止...... Hoogle时间!
你知道吗,Hoogle告诉你一个函数来自哪个模块? Hoolging map会在搜索页面上生成此信息:
map ::(a - > b) - > [a] - >并[b]
base Prelude,base Data.List
这意味着地图已在Prelude
和Data.List
中定义。您可以勾选其他功能,同样看到它们确实在Prelude中。
您还可以查看Haskell 2010 > Standard Prelude或the Prelude hackage docs。
因此我们被允许map
,filter
和foldr
以及Prelude中的其他任何内容。非常好。让我们从Landei的想法开始,将列表转换为列表列表。
groupSorted :: [a] -> [[a]]
groupSorted = undefined
-- groupSorted [1,1,2,2,3,3] ==> [[1,1],[2,2],[3,3]]
我们应该如何实施groupSorted
?好吧,我不知道。我们稍后再考虑一下。假装我们已经实现了它。我们如何使用它来获得正确的解决方案?我假设可以选择一个正确的解决方案,如果有多个(如第二个例子)。
mode :: [a] -> a
mode xs = doSomething (groupSorted xs)
where doSomething :: [[a]] -> a
doSomething = undefined
-- doSomething [[1],[2],[3,3]] ==> 3
-- mode [1,2,3,3] ==> 3
我们在列表中使用groupSorted
之后需要做一些事情。但是什么?嗯......我们应该在列表列表中找到最长的列表。对?这将告诉我们哪个元素在原始列表中出现最多。然后,一旦我们找到最长的子列表,我们想要返回其中的元素。
chooseLongest :: [[a]] -> a
chooseLongest xs = head $ chooseBy (\ys -> length ys) xs
where chooseBy :: ([a] -> b) -> [[a]] -> a
chooseBy f zs = undefined
-- chooseBy length [[1],[2],[3,3]] ==> [3,3]
-- chooseLongest [[1],[2],[3,3]] ==> 3
chooseLongest
是之前的doSomething
。我们的想法是,我们要在列表xs
列表中选择最佳列表,然后选择其中一个元素(其head
就可以了)。我通过创建一个更通用的函数chooseBy
来定义它,它使用一个函数(在这种情况下,我们使用length
函数)来确定哪个选项是最好的。
现在我们处于“艰难”的角色。倍。 chooseBy
和groupSorted
都是折叠。我将引导您完成groupSorted
,并将chooseBy
留给您。
如何编写自己的折叠
我们知道groupSorted
是一个折叠,因为它会消耗整个列表,并产生一些全新的东西。
groupSorted :: [Int] -> [[Int]]
groupSorted xs = foldr step start xs
where step :: Int -> [[Int]] -> [[Int]]
step = undefined
start :: [[Int]]
start = undefined
我们需要选择初始值start
和步进函数step
。我们知道他们的类型,因为foldr
的类型是(a -> b -> b) -> b -> [a] -> b
,在这种情况下,a
是Int
(因为xs
是[Int]
,与[a]
)对齐,而我们想要最终得到的b
是[[Int]]
。
现在请记住,步进函数将逐个检查列表的元素,并使用step
将它们融合到累加器中。我将调用当前检查的元素v
和累加器acc
。
step v acc = undefined
请记住,从理论上讲,foldr
从右到左都是有效的。所以假设我们有列表[1,2,3,3]
。让我们逐步完成算法,从最右边的3
开始,然后继续前进。
step 3 start = [[3]]
无论start
是什么,当我们将其与3
结合使用时,它应该最终为[[3]]
。我们知道这一点,因为如果groupSorted
的原始输入列表只是[3]
,那么我们希望[[3]]
作为结果。但是,它不只是[3]
。我们现在假装它只是[3,3]
。 [[3]]
是新的累加器,我们想要的结果是[[3,3]]
。
step 3 [[3]] = [[3,3]]
我们应该如何处理这些投入?好吧,我们应该将3
添加到内部列表中。但下一步呢?
step 2 [[3,3]] = [[2],[3,3]]
在这种情况下,我们应该创建一个包含2的新列表。
step 1 [[2],[3,3]] = [[1],[2],[3,3]]
就像上次一样,在这种情况下,我们应该在其中创建一个包含1的新列表。
此时我们遍历了整个输入列表,并获得了最终结果。那么我们如何定义step
?似乎有两种情况,具体取决于v
和acc
之间的比较。
step v acc@((x:xs):xss) | v == x = (v:x:xs) : xss
| otherwise = [v] : acc
在一种情况下,v
与acc
中第一个子列表的头部相同。在这种情况下,我们将v
添加到同一个子列表中。但如果情况并非如此,那么我们将v
放在自己的列表中,并将其添加到acc
。那么start
应该是什么?嗯,需要特殊待遇;我们只需使用[]
并为其添加特殊模式匹配。
step elem [] = [[elem]]
start = []
你有它。你只需要确定start
和step
是什么,就可以了解你所做的一切。通过一些清理和eta减少:
groupSorted = foldr step []
where step v [] = [[v]]
step v acc@((x:xs):xss)
| v == x = (v:x:xs) : xss
| otherwise = [v] : acc
这可能不是最有效的解决方案,但它有效,如果您以后需要优化,至少可以了解此功能的工作原理。
答案 2 :(得分:2)
我不想破坏所有的乐趣,但group
函数会有所帮助。不幸的是,它是在Data.List
中定义的,所以你需要自己编写。一种可能的方式是:
-- corrected version, see comments
grp [] = []
grp (x:xs) = let a = takeWhile (==x) xs
b = dropWhile (==x) xs
in (x : a) : grp b
E.g。 grp [1,1,2,2,3,3,3]
给出[[1,1],[2,2],[3,3,3]]
。我想从那里你可以自己找到解决方案。
答案 3 :(得分:0)
我会尝试以下方法:
mostFrequent = snd . foldl1 max . map mark . group
where
mark (a:as) = (1 + length as, a)
mark [] = error "cannot happen" -- because made by group
请注意,它适用于包含可排序元素的任何有限列表,而不仅仅是整数。