2010-06-23 16 views
46

okay, das wird wahrscheinlich im Vorspiel sein, aber: gibt es eine Standard-Bibliotheksfunktion zum Finden der einzigartigen Elemente in einer Liste? meine (Wieder-) Einführung, zur Klarstellung, ist:einzigartige Elemente in einer Haskell-Liste

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 
+10

Ihre 'has' ist ebenfalls Standard; Es ist nur "Flip Elem". – Nefrubyr

+3

Oder sogar 'hat xs = (\' elem \ 'xs)'. – yatima2975

+0

@ yatima2975 Warum benutzt du 'elem' als Infix? – dopatraman

Antwort

45

Die nub Funktion von Data.List (nein, es ist eigentlich nicht im Prelude) macht definitiv etwas wie das, was Sie wollen, aber es ist nicht ganz das gleiche wie Ihre unique Funktion. Sie beide die ursprüngliche Reihenfolge der Elemente erhalten, sondern behält den letzten unique Auftreten jedes Elements, während das erste Vorkommen nub beibehält.

können Sie tun dies nub Tat genau wie unique zu machen, wenn das wichtig ist (obwohl ich das Gefühl habe, es ist nicht):

unique = reverse . nub . reverse 

Auch nub für kleine Listen nur gut ist. Seine Komplexität ist quadratisch, so beginnt es langsam zu erhalten, wenn Ihre Liste Hunderte von Elementen enthalten.

Wenn Sie Ihre Typen Typen begrenzen eine Ord Instanz haben, können Sie es besser machen skalieren. Diese Variante nub bewahrt noch die Reihenfolge der Listenelemente, aber seine Komplexität ist 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 _ _    = [] 

In der Tat, es proposednubOrd-Data.Set hinzuzufügen war.

+1

Wohl sein Bestes, es einfach als Set zu verlassen, anstatt eine Liste an erster Stelle zu verwenden – alternative

+0

Seien wir ehrlich: 'nub' ist nicht gut für alle Liste. Selbst auf der Liste mit 2 Elementen ist 'nubOrd' [schneller] (https://github.com/nh2/haskell-ordnub#dont-use-nub). – nh2

+0

Dies ist ein bisschen wie ein "Kartensieb" ähnlich dem unreinen "Haschsieb". – CMCDragonkai

88

ich für (Eq a) => [a] -> [a] auf Hoogle gesucht.

Erstes Ergebnis war nub (um doppelte Elemente aus einer Liste).

Hoogle ist genial.

+1

Auch können Sie Ihre eigene Gleichheitsfunktion wie diese zur Verfügung stellen: nubBy :: (a -> a -> Bool) -> [a] -> [a] –

+0

Und wenn Bart jemals Zeit bekommt, sehen wir vielleicht einen nubOrd, das wird vernünftigerweise leistungsfähiger sein. –

+2

Es ist erwähnenswert, dass die Funktion 'nub' aus dem Paket' Data.List' stammt. –

4

Ich denke, dass Unique sollte eine Liste von Elementen, die nur einmal in der ursprünglichen Liste angezeigt werden; Das heißt, alle Elemente der Originalliste, die mehr als einmal angezeigt werden, sollten nicht im Ergebnis enthalten sein.

Darf ich vorschlagen, eine alternative Definition, 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) 

Hier sind einige Beispiele, die die Unterschiede zwischen unique_alt und unqiue markieren:

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

Das ist in der Tat die Definition von Data.List.Unique (einzigartig) obwohl persönlich, ich habe nie zu diesem Anwendungsfall gelaufen, während die "Squash-Listen enthalten nur eine der Duplikate" -Funktion ist Brot und Butter von vielen Operationen. –

8
import Data.Set (toList, fromList) 
uniquify lst = toList $ fromList lst 
+24

'uniquify = toList. fromList' – muhmuhten

+1

Dies ändert die Reihenfolge der Elemente. – sjakobi

-1

Ein anderer Weg, um Duplikate zu entfernen:

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

Algorithmus in Haskell eine einzigartige Liste zu erstellen:

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) 

Ausgang:

Foo {id_ = 9, name_ = "Name"} 
Foo {id_ = 9, name_ = "Gaby"} 
Foo {id_ = 5, name_ = "Karl"} 
Foo {id_ = 8, name_ = "Tim"} 
Verwandte Themen