Algorithm 识别Haskell元组中的重复项

Algorithm 识别Haskell元组中的重复项,algorithm,haskell,non-deterministic,Algorithm,Haskell,Non Deterministic,我正在尝试编写一个函数,如果元组中的任意两个值相同,它将NothingaJustInt元组。对于五个值的元组,这里是我得到的。显然,还有改进的余地: nothingIfMatch :: Maybe (Int, Int, Int, Int, Int) -> Maybe (Int, Int, Int, Int, Int) nothingIfMatch Nothing = Nothing nothingIfMatch (Just (a, b, c, d, e)) | a == b = N

我正在尝试编写一个函数,如果元组中的任意两个值相同,它将
Nothing
a
Just
Int
元组。对于五个值的元组,这里是我得到的。显然,还有改进的余地:

nothingIfMatch :: Maybe (Int, Int, Int, Int, Int) -> Maybe (Int, Int, Int, Int, Int)
nothingIfMatch Nothing = Nothing
nothingIfMatch (Just (a, b, c, d, e))
    | a == b = Nothing
    | a == c = Nothing
    | a == d = Nothing
    | a == e = Nothing
    | b == c = Nothing
    | b == d = Nothing
    | b == e = Nothing
    | c == d = Nothing
    | c == e = Nothing
    | d == e = Nothing
    | otherwise = Just (a, b, c, d, e)
考虑到一个n元组有“n选择2”可能的交点,在这种情况下,只有10个选项。但是想象一下,这是一个8元组,有28种可能,或者是一个10元组,有45种可能

必须有一种更惯用的方法来实现这一点,可能依赖于非决定论特性


应如何执行此操作?

我们可以首先生成
Int
s列表,然后执行所有相等性检查:

import Data.List(tails)

twoEqual :: Eq a => [a] -> Bool
twoEqual xs = any (uncurry elem) [(h, t) | (h:t) <- tails xs]
我们可以很容易地向元组中添加一个额外的元素,并将其添加到
twoEqual
调用中的列表中。这里我们仍然执行O(n2)。如果我们可以先对元素排序,我们可以在O(n logn)中进行排序,或者如果元素是可散列的并且没有散列冲突发生,我们甚至可以在O(n)中进行排序

例如:

-- O(n log n) if the elements can be ordered

import Data.List(sort, tails)

twoEqual :: Ord a => [a] -> Bool
twoEqual xs = or [h1 == h2 | (h1:h2:_) <- tails (sort xs)]

为了将来读者的利益,可以添加一些关于如何工作的信息吗?在“no-
Ord
-available”的情况下,可以编写
twoEqual xs=xs==Data.List.nub xs
。我喜欢它的简洁性和模块性;特别是因为一旦你理解了它,你就可以立即用几乎相同的方式写下“
Ord
-available”一词:
twoEquals xs_=xs==Data.List.Ordered.nub xs,其中xs=sort xs_=xs
。如果你需要在一个结构中存储任意数量的一种类型的数据,你可能需要使用某种列表,而不是元组。考虑例如<代码>可能[INT] < /代码>或<代码>(Vector Int)< /代码>
-- O(n log n) if the elements can be ordered

import Data.List(sort, tails)

twoEqual :: Ord a => [a] -> Bool
twoEqual xs = or [h1 == h2 | (h1:h2:_) <- tails (sort xs)]
-- O(n) in case the elements are hashable and no hash collisions

import Data.Hashable(Hashable)
import Data.HashSet(fromList, member)

twoEqual :: (Hashable a, Ord a) => [a] -> Bool
twoEqual xs = any (flip member hs) xs
    where hs = fromList xs