62 votes

éléments uniques dans une liste haskell

Ok, cela va probablement être dans le prélude, mais : existe-t-il une fonction de la bibliothèque standard pour trouver les éléments uniques d'une liste ? ma (ré)implémentation, pour clarification, est la suivante :

has :: (Eq a) => [a] -> a -> Bool
has [] _ = False
has (x:xs) a
  | x == a    = True
  | otherwise = has xs a

unique :: (Eq a) => [a] -> [a]
unique [] = []
unique (x:xs)
  | has xs x  = unique xs
  | otherwise = x : unique xs

14 votes

Su has est également standard ; c'est juste flip elem .

5 votes

Ou même has xs = (`elem` xs) .

0 votes

@yatima2975 pourquoi utilisez-vous elem en tant qu'infixe ?

105voto

Artelius Points 25772

J'ai cherché (Eq a) => [a] -> [a] sur Hoogle .

Le premier résultat était nub (supprimer les éléments en double d'une liste).

Hoogle est génial.

1 votes

Vous pouvez également fournir votre propre fonction d'égalité comme ceci : nubBy : : (a -> a -> Bool) -> [a] -> [a]

0 votes

Et si Bart a le temps, nous pourrions voir un nubOrd, qui sera plus raisonnable en termes de performances.

2 votes

Il faut dire que le nub La fonction est issue de Data.List paquet.

58voto

Yitz Points 3262

El nub de la fonction Data.List (non, ce n'est pas vraiment dans le Prelude) fait quelque chose qui ressemble à ce que vous voulez, mais ce n'est pas tout à fait pareil que votre unique fonction. Ils conservent tous deux l'ordre original des éléments, mais unique conserve la dernière de chaque élément, tandis que nub conserve la première occurrence.

Vous pouvez faire cela pour faire nub agissent exactement comme unique si c'est important (mais j'ai le sentiment que ce n'est pas le cas) :

unique = reverse . nub . reverse

Aussi, nub n'est bon que pour les petites listes. Sa complexité est quadratique, et elle commence à être lente si votre liste peut contenir des centaines d'éléments.

Si vous limitez vos types aux types ayant une instance Ord, vous pouvez améliorer l'échelle. Cette variation sur nub préserve toujours l'ordre des éléments de la liste, mais sa complexité est plus grande. O(n * log n) :

import qualified Data.Set as Set

nubOrd :: Ord a => [a] -> [a] 
nubOrd xs = go Set.empty xs where
  go s (x:xs)
   | x `Set.member` s = go s xs
   | otherwise        = x : go (Set.insert x s) xs
  go _ _              = []

En fait, il a été proposée à ajouter nubOrd a Data.Set .

1 votes

On peut dire qu'il est préférable de le laisser simplement comme un ensemble plutôt que d'utiliser une liste en premier lieu.

1 votes

Soyons honnêtes : nub n'est bon pour aucune liste. Même sur la liste avec 2 éléments nubOrd es plus rapide .

0 votes

Il s'agit en quelque sorte d'un "tamis de carte" semblable au "tamis de hachage" impur.

13voto

dpatru Points 353
import Data.Set (toList, fromList)
uniquify lst = toList $ fromList lst

6 votes

Cela change l'ordre des éléments.

4voto

Adam Grant Points 41

Je pense que unique devrait retourner une liste d'éléments qui n'apparaissent qu'une seule fois dans la liste originale ; c'est-à-dire que tout élément de la liste originale qui apparaît plus d'une fois ne devrait pas être inclus dans le résultat.

Puis-je suggérer une autre définition, unique_alt :

    unique_alt :: [Int] -> [Int]
    unique_alt [] = []
    unique_alt (x:xs)
        | elem x ( unique_alt xs ) = [ y | y <- ( unique_alt xs ), y /= x ]
        | otherwise                = x : ( unique_alt xs )

Voici quelques exemples qui mettent en évidence les différences entre unique_alt et unqiue :

    unique     [1,2,1]          = [2,1]
    unique_alt [1,2,1]          = [2]

    unique     [1,2,1,2]        = [1,2]
    unique_alt [1,2,1,2]        = []

    unique     [4,2,1,3,2,3]    = [4,1,2,3]
    unique_alt [4,2,1,3,2,3]    = [4,1]

0 votes

C'est en fait la définition de Data.List.Unique (unique) bien que personnellement, je n'ai jamais rencontré ce cas d'utilisation, alors que la fonction "écraser les listes pour qu'elles ne contiennent qu'un seul des doublons" est le pain et le beurre de nombreuses opérations.

0voto

Juan Kujarchi Points 9

Une autre façon de supprimer les doublons :

unique :: [Int] -> [Int]
unique xs = [x | (x,y) <- zip xs [0..], x `notElem` (take y xs)]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X