简体   繁体   English

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

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

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

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

Yes, it's concat from the Standard Prelude, given by 是的,它是concat从标准前奏, 由下式给出

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

If you want to turn [[[a]]] into [a] , you must use it twice: 如果要将[[[a]]]变成[a] ,则必须使用它两次:

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

Since nobody else has given this, it is possible to define a function which will flatten lists of an arbitrary depth by using MultiParamTypeClasses. 由于没有其他人给出这个,因此可以定义一个函数,该函数将使用MultiParamTypeClasses展平任意深度的列表。 I haven't actually found it useful, but hopefully it could be considered an interesting hack. 我实际上并没有发现它有用,但希望它可以被认为是一个有趣的黑客。 I got the idea from Oleg's polyvariadic function implementation. 我从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

Now if you load it and run in ghci: 现在,如果你加载它并在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]

Note that it's usually necessary to provide the result type annotation, because otherwise ghc can't figure out where to stop recursively applying the flatten class method. 请注意,通常需要提供结果类型注释,否则ghc无法确定在何处停止递归应用flatten类方法。 If you use a function with a monomorphic type that's sufficient however. 如果你使用的单态类型的函数就足够了。

*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

As others have pointed out, concat :: [[a]] -> [a] is the function you are looking for, and it can't flatten nested lists of arbitrary depth. 正如其他人所指出的那样, concat :: [[a]] -> [a]是你正在寻找的函数,它不能展平任意深度的嵌套列表。 You need to call it multiple times to flatten it down to the desired level. 您需要多次调用它以将其展平至所需级别。

The operation does generalize to other monads, though. 不过,该操作确实可以推广到其他monad。 It is then known as join , and has the type Monad m => m (ma) -> ma . 然后它被称为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]

As hammar pointed out, join is the "monadic" way to flatten a list. 正如哈马尔指出的那样, join是压缩名单的“monadic”方式。 You can use the do -Notation as well to write easily flatten functions of several levels: 您也可以使用do -otation来轻松编写几个级别的平面函数:

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

An arbitrarily nested list can be approximated by a Data.Tree , which can be flattened by the appropriately named function flatten . 任意嵌套的列表可以通过Data.Tree来近似,可以通过适当命名的函数flatten

I say approximated because Data.Tree allows a data item to be attached to every node, not just the leaves. 我说近似因为Data.Tree允许将数据项附加到每个节点,而不仅仅是叶子。 However, you could create a Data.Tree (Maybe a) , and attach Nothing to the body nodes, and flatten with catMaybes . flatten 但是,您可以创建一个Data.Tree (Maybe a) ,并将Nothing附加到body节点,并使用catMaybes . flatten展平catMaybes . flatten catMaybes . flatten . catMaybes . flatten

You can remove one level of nesting using concat , and consequently you can apply n levels of nesting by applying concat n times. 您可以使用concat删除一级嵌套,因此可以通过应用concat n次来应用n级嵌套。

It is not possible to write a function which removes an arbitrary level of nestings, as it is not possible to express the type of a function, which takes an arbitrarily nested list and returns a flat list, using Haskell's type system (using the list datatype that is - you can write your own datatype for arbitrarily nested lists and write a flatten function for that). 这是不可能的(使用列表数据类型写入一个函数,它消除嵌套的任意水平,因为它不能够表达一个函数,该函数的任意嵌套列表并返回一个平坦的列表,使用Haskell的类型系统的类型也就是说 - 你可以为任意嵌套的列表编写自己的数据类型,并为此编写一个flatten函数。

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

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