找到最嵌套的列表

时间:2014-04-14 15:27:13

标签: list haskell functional-programming nested-lists

我有以下类型:

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])

1 个答案:

答案 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之前的各种功能(从顶部开始),以便您可以看到每一步的外观,它应该可以帮助您实现算法好一点。