d'accord, cela va probablement être dans le prélude, mais: existe-t-il une fonction de bibliothèque standard pour trouver les éléments uniques dans une liste? ma (re) mise en œuvre, pour clarification, est:
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
La fonction nub
de Data.List
(non, ce n'est pas dans le prélude) fait certainement quelque chose comme ce que vous voulez, mais ce n'est pas tout à fait la même chose que votre fonction unique
. Ils conservent tous les deux l'ordre d'origine des éléments, mais unique
conserve la dernière occurrence De chaque élément, tandis que nub
conserve la première occurrence.
Vous pouvez faire cela pour que nub
agisse exactement comme unique
, si c'est important (même si j'ai l'impression que ce n'est pas le cas):
unique = reverse . nub . reverse
De plus, nub
n'est utile que pour les petites listes . Sa complexité est quadratique, elle commence donc à devenir lente si votre liste peut contenir des centaines d'éléments.
Si vous limitez vos types aux types ayant une instance Ord, vous pouvez la rendre plus évolutive . Cette variation sur nub
conserve toujours l'ordre des éléments de la liste, mais sa complexité est 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 _ _ = []
import Data.Set (toList, fromList)
uniquify lst = toList $ fromList lst
Je pense que cet unique devrait renvoyer une liste d'éléments qui n'apparaissent qu'une fois dans la liste d'origine; c'est-à-dire que tous les éléments de la liste originale qui apparaissent plus d'une fois ne doivent 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 soulignent 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]
Je pense que cela le ferait.
unique [] = []
unique (x:xs) = x:unique (filter ((/=) x) xs)
Une autre façon de supprimer les doublons:
unique :: [Int] -> [Int]
unique xs = [x | (x,y) <- Zip xs [0..], x `notElem` (take y xs)]
Algorithme dans Haskell pour créer une liste unique:
data Foo = Foo { id_ :: Int
, name_ :: String
} deriving (Show)
alldata = [ Foo 1 "Name"
, Foo 2 "Name"
, Foo 3 "Karl"
, Foo 4 "Karl"
, Foo 5 "Karl"
, Foo 7 "Tim"
, Foo 8 "Tim"
, Foo 9 "Gaby"
, Foo 9 "Name"
]
isolate :: [Foo] -> [Foo]
isolate [] = []
isolate (x:xs) = (fst f) : isolate (snd f)
where
f = foldl helper (x,[]) xs
helper (a,b) y = if name_ x == name_ y
then if id_ x >= id_ y
then (x,b)
else (y,b)
else (a,y:b)
main :: IO ()
main = mapM_ (putStrLn . show) (isolate alldata)
Sortie:
Foo {id_ = 9, name_ = "Name"}
Foo {id_ = 9, name_ = "Gaby"}
Foo {id_ = 5, name_ = "Karl"}
Foo {id_ = 8, name_ = "Tim"}