我有以下类型:
data NestedList a = Elem a | List [NestedList a]
我正在尝试编写一个返回给定列表中嵌套列表最多的函数,但我不知道从哪里开始。任何帮助表示赞赏!
示例:
函数的输入类似于:
(List [List [List [List [Elem 1, Elem 2, Elem 3], Elem 5, Elem 6], List [Elem 5, Elem 6]], List [Elem 5, Elem 6]])
期望的功能输出:
(List [Elem 1, Elem 2, Elem 3])
答案 0 :(得分:2)
我将举一个使用二叉树的例子,它与你的结构非常相似。您可以将其转换为适用于您的数据类型。
说我有一棵二叉树
data Tree a
= Leaf a
| Node (Tree a) (Tree a)
deriving (Eq, Show)
我希望找到具有最大深度的值(可以有多个!)。我如何解决这个问题的方法是递归遍历每个分支,记录深度,然后返回底部的值及其深度。
首先,我将定义我的功能结构
import Data.List (sortBy, groupBy)
import Data.Ord (comparing)
import Data.Function (on)
getDeepest :: Tree a -> [a]
getDeepest tree
= map fst -- Strip the depth from the values
. head -- Get just the ones with the largest depth
. groupBy ((==) `on` snd) -- Group by the depth
. sortBy (flip (comparing snd)) -- Reverse sort by the depth (largest first)
$ go tree 0 -- Find all the "bottom" nodes
where
go :: Tree a -> Int -> [(a, Int)]
go (Leaf a) n = undefined
go (Node l r) n = undefined
这是一种常见的递归格式,您将在Haskell中看到。我有一个本地帮助函数,它带有一个我想要在特定值初始化的附加值,在这种情况下是深度0
。我已经包含了我想知道的逻辑,以便以良好的格式获得输出。 flip (comparing snd)
将进行反向排序,因此最大深度将首先出现。然后我们按深度分组,提取第一组,然后从值中去除深度。
现在我们只需定义go
的作用。我们知道当我们触及底部时,我们希望使用我们找到的深度将值添加到累加器中,所以
go (Leaf a) n = [(a, n)]
这种情况非常简单,我们只需从值和深度创建一个元组,并将其作为列表包装。对于另一种情况,我们想要遍历每个分支,找到最深的元素,并从两个分支返回最深的
go (Node l r) n = go l (n + 1) ++ go r (n + 1)
这是递归发生的地方。虽然这当然不是最有效的算法(Haskell列表对此并不好,但我们将简单地使用它们),它仍然非常简单。我们所做的就是沿着每一边往下走,并将我们的深度增加1
。所以整个算法在一起:
getDeepest :: Tree a -> [a]
getDeepest tree
= map fst -- Strip the depth from the values
. head -- Get just the ones with the largest depth
. groupBy ((==) `on` snd) -- Group by the depth
. sortBy (flip (comparing snd)) -- Reverse sort by the depth (largest first)
$ go tree 0 -- Find all the "bottom" nodes
where
go :: Tree a -> Int -> [(a, Int)]
go (Leaf a) n = [(a, n)]
go (Node l r) n = go l (n + 1) ++ go r (n + 1)
以此为例:
myTree :: Tree Int
myTree =
Node
(Node
(Leaf 1)
(Node
(Leaf 2)
(Leaf 3)))
(Leaf 4)
可以将其视为
Node
/ \
Node Leaf 4
/ \
Leaf 1 Node
/ \
Leaf 2 Leaf 3
然后通过应用getDeepest
返回[2, 3]
。我建议您从getDeepest
删除类型签名并尝试删除go tree 0
之前的各种功能(从顶部开始),以便您可以看到每一步的外观,它应该可以帮助您实现算法好一点。