簡體   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