繁体   English   中英

是否有一个函数来展平嵌套的元素列表?

[英]Is there a function to flatten a nested list of elements?

如何拼合这样的嵌套列表:

[1, 2, 3, 4] == flatten [[[1,2],[3]],[[4]]]

是的,它是concat从标准前奏, 由下式给出

concat :: [[a]] -> [a]
concat xss = foldr (++) [] xss

如果要将[[[a]]]变成[a] ,则必须使用它两次:

Prelude> (concat . concat) [[[1,2],[3]],[[4]]]
[1,2,3,4]

由于没有其他人给出这个,因此可以定义一个函数,该函数将使用MultiParamTypeClasses展平任意深度的列表。 我实际上并没有发现它有用,但希望它可以被认为是一个有趣的黑客。 我从Oleg的多变量函数实现中得到了这个想法。

{-# LANGUAGE MultiParamTypeClasses, OverlappingInstances, FlexibleInstances #-}

module Flatten where

class Flatten i o where
  flatten :: [i] -> [o]

instance Flatten a a where
  flatten = id

instance Flatten i o => Flatten [i] o where 
  flatten = concatMap flatten

现在,如果你加载它并在ghci中运行:

*Flatten> let g = [1..5]
*Flatten> flatten g :: [Integer]
[1,2,3,4,5]
*Flatten> let h = [[1,2,3],[4,5]]
*Flatten> flatten h :: [Integer]
[1,2,3,4,5]
*Flatten> let i = [[[1,2],[3]],[],[[4,5],[6]]]
*Flatten> :t i
i :: [[[Integer]]]
*Flatten> flatten i :: [Integer]
[1,2,3,4,5,6]

请注意,通常需要提供结果类型注释,否则ghc无法确定在何处停止递归应用flatten类方法。 如果你使用的单态类型的函数就足够了。

*Flatten> :t sum
sum :: Num a => [a] -> a
*Flatten> sum $ flatten g

<interactive>:1:7:
    No instance for (Flatten Integer a0)
      arising from a use of `flatten'
    Possible fix: add an instance declaration for (Flatten Integer a0)
    In the second argument of `($)', namely `flatten g'
    In the expression: sum $ flatten g
    In an equation for `it': it = sum $ flatten g
*Flatten> let sumInt = sum :: [Integer] -> Integer
*Flatten> sumInt $ flatten g
15
*Flatten> sumInt $ flatten h
15

正如其他人所指出的那样, concat :: [[a]] -> [a]是你正在寻找的函数,它不能展平任意深度的嵌套列表。 您需要多次调用它以将其展平至所需级别。

不过,该操作确实可以推广到其他monad。 然后它被称为join ,并且具有Monad m => m (ma) -> ma

Prelude Control.Monad> join [[1, 2], [3, 4]]
[1,2,3,4]    
Prelude Control.Monad> join (Just (Just 3))
Just 3
Prelude Control.Monad.Reader> join (+) 21
42
import Data.List
let flatten = intercalate []

flatten $ flatten [[[1,2],[3]],[[4]]]
[1,2,3,4]

正如哈马尔指出的那样, join是压缩名单的“monadic”方式。 您也可以使用do -otation来轻松编写几个级别的平面函数:

flatten xsss = do xss <- xsss
                  xs <- xss
                  x <- xs
                  return x

任意嵌套的列表可以通过Data.Tree来近似,可以通过适当命名的函数flatten

我说近似因为Data.Tree允许将数据项附加到每个节点,而不仅仅是叶子。 但是,您可以创建一个Data.Tree (Maybe a) ,并将Nothing附加到body节点,并使用catMaybes . flatten展平catMaybes . flatten catMaybes . flatten

您可以使用concat删除一级嵌套,因此可以通过应用concat n次来应用n级嵌套。

这是不可能的(使用列表数据类型写入一个函数,它消除嵌套的任意水平,因为它不能够表达一个函数,该函数的任意嵌套列表并返回一个平坦的列表,使用Haskell的类型系统的类型也就是说 - 你可以为任意嵌套的列表编写自己的数据类型,并为此编写一个flatten函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM