さて、これはおそらく前奏曲になるでしょうが、リスト内の一意の要素を見つけるための標準ライブラリ関数はありますか?明確化のための私の(再)実装は次のとおりです。
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
_Data.List
_からのnub
関数(いいえ、実際にはPreludeにはありません)は間違いなくあなたが望むもののようなことをしますが、それはunique
関数と全く同じではありません。どちらも元の要素の順序を保持しますが、unique
は各要素の最後の出現を保持し、nub
は最初の出現を保持します。
これを行うと、nub
がunique
とまったく同じように動作するようになります(それが重要な場合)(そうではないと感じていますが)。
_unique = reverse . nub . reverse
_
また、nub
は小さなリストにのみ適しています。その複雑さは二次関数なので、リストに何百もの要素を含めることができる場合は遅くなり始めます。
タイプをOrdインスタンスを持つタイプに制限すると、スケールを改善できます。 nub
のこのバリエーションはリスト要素の順序を保持しますが、その複雑さは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 _ _ = []
_
実際、nubOrd
を_Data.Set
_に追加することは proposed でした。
import Data.Set (toList, fromList)
uniquify lst = toList $ fromList lst
Uniqueは、元のリストに一度しか現れない要素のリストを返すべきだと思います。つまり、元のリストの要素のうち、複数回出現するものは結果に含めないでください。
別の定義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 )
以下に、unique_altと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]
これでうまくいくと思います。
unique [] = []
unique (x:xs) = x:unique (filter ((/=) x) xs)
重複を削除する別の方法:
unique :: [Int] -> [Int]
unique xs = [x | (x,y) <- Zip xs [0..], x `notElem` (take y xs)]
一意のリストを作成するHaskellのアルゴリズム:
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)
出力:
Foo {id_ = 9, name_ = "Name"}
Foo {id_ = 9, name_ = "Gaby"}
Foo {id_ = 5, name_ = "Karl"}
Foo {id_ = 8, name_ = "Tim"}