识别Haskell元组中的重复项

时间:2018-05-01 11:34:58

标签: algorithm haskell non-deterministic

如果元组中的任何两个值相同,我正在尝试编写一个Nothing 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种。

必须采用更惯用的方法,可能依赖于非确定性功能。

应该怎么做?

1 个答案:

答案 0 :(得分:5)

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

import Data.List(tails)

twoEqual :: Eq a => [a] -> Bool
twoEqual xs = any (uncurry elem) [(h, t) | (h:t) <- tails xs]

这里我们首先为列表中的每个元素生成一个元组,其中包含元素和列表的 rest 。然后我们执行elem个函数:我们在项目和列表的其余部分调用elem,如果这些检查的any成立,则返回True,{{ 1}}否则。

现在我们可以从这个元组构造一个列表,然后使用一个guard来执行检查:

False

我们可以轻松地向元组添加一个额外元素,并将其添加到nothingIfMatch :: Eq a => Maybe (a, a, a, a, a) -> Maybe (a, a, a, a, a) nothingIfMatch = (>>= f) where f r@(a, b, c, d, e) | twoEqual [a, b, c, d, e] = Nothing | otherwise = Just r 调用中的列表中。在这里,我们仍然执行 O(n 2 。我们可以在 O(n log n)中进行,如果我们可以先排序元素,或者我们甚至可以在 O(n)中进行,以防元素< em> hashable 并且不会发生哈希冲突。

例如:

twoEqual

或者可以对元素进行哈希处理:

-- 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)]