web-dev-qa-db-ja.com

Haskellリスト内の一意の要素

さて、これはおそらく前奏曲になるでしょうが、リスト内の一意の要素を見つけるための標準ライブラリ関数はありますか?明確化のための私の(再)実装は次のとおりです。

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
50
muhmuhten

_Data.List_からのnub関数(いいえ、実際にはPreludeにはありません)は間違いなくあなたが望むもののようなことをしますが、それはunique関数と全く同じではありません。どちらも元の要素の順序を保持しますが、uniqueは各要素の最後の出現を保持し、nubは最初の出現を保持します。

これを行うと、nubuniqueとまったく同じように動作するようになります(それが重要な場合)(そうではないと感じていますが)。

_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 でした。

50
Yitz

Google(Eq a) => [a] -> [a]を検索しました。

最初の結果は nub (リストから重複した要素を削除する)でした。

Hoogleは素晴らしいです。

91
Artelius
import Data.Set (toList, fromList)
uniquify lst = toList $ fromList lst
10
dpatru

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]
4
Adam Grant

これでうまくいくと思います。

unique [] = []
unique (x:xs) = x:unique (filter ((/=) x) xs)
1
Craig Norton

重複を削除する別の方法:

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

一意のリストを作成する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"}
0
Manuel