web-dev-qa-db-fra.com

Existe-t-il une fonction pour aplatir une liste d'éléments imbriqués?

Comment aplatir une liste imbriquée comme ceci:

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

Puisque personne d'autre ne l'a donné, il est possible de définir une fonction qui aplatira les listes d'une profondeur arbitraire en utilisant MultiParamTypeClasses. Je ne l'ai pas vraiment trouvé utile, mais j'espère que cela pourrait être considéré comme un hack intéressant. J'ai eu l'idée de l'implémentation de la fonction polyvariade d'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

Maintenant, si vous le chargez et exécutez dans 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]

Notez qu'il est généralement nécessaire de fournir l'annotation du type de résultat, car sinon ghc ne peut pas savoir où arrêter récursivement l'application de la méthode de classe flatten. Si vous utilisez une fonction avec un type monomorphe, cela suffit cependant.

*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
43
John L

Oui, c'est concat du Prélude Standard, donné par

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

Si vous souhaitez activer [[[a]]] en [a], vous devez l'utiliser deux fois:

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

Comme d'autres l'ont souligné, concat :: [[a]] -> [a] Est la fonction que vous recherchez, et elle ne peut pas aplatir des listes imbriquées de profondeur arbitraire. Vous devez l'appeler plusieurs fois pour l'aplatir au niveau souhaité.

L'opération se généralise cependant à d'autres monades. Il est alors appelé join et a le type 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
12
hammar
import Data.List
let flatten = intercalate []

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

Comme l'a souligné Hammar, join est le moyen "monadique" d'aplatir une liste. Vous pouvez également utiliser la notation do- pour écrire des fonctions d'aplatissement de plusieurs niveaux:

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

Une liste imbriquée arbitrairement peut être approximée par un Data.Tree, Qui peut être aplati par la fonction nommée de manière appropriée flatten.

Je dis approximé parce que Data.Tree Permet à un élément de données d'être attaché à chaque nœud, pas seulement aux feuilles. Cependant, vous pouvez créer une Data.Tree (Maybe a), et attacher Nothing aux nœuds du corps, et aplatir avec catMaybes . flatten.

4
pat

Vous pouvez supprimer un niveau d'imbrication à l'aide de concat et, par conséquent, vous pouvez appliquer n niveaux d'imbrication en appliquant concat n fois.

Il n'est pas possible d'écrire une fonction qui supprime un niveau arbitraire d'imbrication, car il n'est pas possible d'exprimer le type d'une fonction, qui prend une liste imbriquée arbitrairement et renvoie une liste plate, en utilisant le système de type de Haskell (en utilisant le type de données de liste c'est-à-dire que vous pouvez écrire votre propre type de données pour des listes imbriquées arbitrairement et écrire une fonction d'aplatissement pour cela).

3
sepp2k