algorithm - 识别 Haskell 元组中的重复项

标签 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 种可能性。

必须有一种更惯用的方法来做到这一点,可能依赖于非确定性特征。

应该怎么做?

最佳答案

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

import Data.List(tails)

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

在这里,我们首先为列表中的每个元素生成一个元组,其中包含该元素和列表的其余。然后我们执行 elem 函数:我们在项目和列表的其余部分上调用 elem,如果这些检查中的 any 成立,那么我们返回 True,否则返回 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

我们可以轻松地向元组添加一个额外的元素,并在 twoEqual 调用中将其添加到列表中。这里我们仍然执行O(n2)。如果我们可以先对元素进行排序,我们可以在 O(n log n) 中完成,或者我们甚至可以在 O(n) 中完成,如果元素是 < em>可散列并且不会发生散列冲突。

例如:

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

关于algorithm - 识别 Haskell 元组中的重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50115770/

相关文章:

haskell - Haskell 中如何解析撇号/字 rune 字?

c# - amb-operator 的非确定性选择

javascript - 如何修改 Elo 评级以获得更大的分差?

绳索触杆算法

haskell - 在简单的 http get 示例中找不到模块 `Network.HTTP'

haskell - 这个用 do 表示法怎么写?

java - Z3多次运行时产生不同的模型

c++ - 使用堆内存(malloc/new)会创建一个不确定的程序吗?

algorithm - 反转并合并链表

algorithm - 角度遮挡算法