[英]Is there a function to flatten a nested list of elements?
如何拼合这样的嵌套列表:
[1, 2, 3, 4] == flatten [[[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.