haskell-是否具有将元素的嵌套列表展平的功能?

我怎样才能展平这样的嵌套列表:

[1, 2, 3, 4] == flatten [[[1,2],[3]],[[4]]]
luqui asked 2019-11-08T17:42:19Z
7个解决方案
112 votes

是的,这是标准前奏曲中的[[[a]]],由

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

如果要将[[[a]]]转换为[a],则必须使用两次:

Prelude> (concat . concat) [[[1,2],[3]],[[4]]]
[1,2,3,4]
Josh Lee answered 2019-11-08T17:43:21Z
44 votes

由于没有其他人提供此功能,因此可以定义一个函数,该函数将通过使用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
John L answered 2019-11-08T17:42:49Z
13 votes

正如其他人指出的那样,join是您要寻找的函数,它不能展平任意深度的嵌套列表。 您需要多次调用以将其展平到所需的水平。

但是,该操作确实可以推广到其他单子。 然后称为join,类型为Monad m => m (m a) -> m a

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
hammar answered 2019-11-08T17:43:53Z
9 votes
import Data.List
let flatten = intercalate []

flatten $ flatten [[[1,2],[3]],[[4]]]
[1,2,3,4]
en4bz answered 2019-11-08T17:44:12Z
8 votes

正如hammar指出的那样,join是扁平化列表的“单子”方式。 您也可以使用do-Notation来编写容易平整的多个级别的函数:

flatten xsss = do xss <- xsss
                  xs <- xss
                  x <- xs
                  return x
Landei answered 2019-11-08T17:44:38Z
4 votes

可以使用2605457921621614021632近似任意嵌套的列表,可以使用适当命名的函数Data.Tree (Maybe a)对其进行展平。

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

pat answered 2019-11-08T17:45:11Z
3 votes

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

无法编写删除任意嵌套级别的函数,因为无法表达使用Haskell的类型系统(使用list数据类型)来获取任意嵌套列表并返回平面列表的函数类型 也就是说-您可以为任意嵌套的列表编写自己的数据类型,并为此编写一个flatten函数)。

sepp2k answered 2019-11-08T17:45:46Z
translate from https://stackoverflow.com:/questions/5994051/is-there-a-function-to-flatten-a-nested-list-of-elements