我需要比较给定列表的所有元素是否唯一。 (为了记录,我这样做是出于学术目的。)
这是我到目前为止所做的:
allDifferent :: (Eq a) => [a] -> Bool
allDifferent list = case list of
[] -> True
(x:xs) -> if x `elem` xs then False else allDifferent xs
哪作得非常好!
现在,当我尝试这样做时......
allDifferent2 :: (Eq a) => [a] -> Bool
allDifferent2 list
| null list = True
| (head list) `elem` (tail list) || allDifferent2 (tail list) = False
| otherwise
它不能按预期工作。 我从GHCi得到以下输出:
*Main> allDifferent2 [1..4]
False
*Main> allDifferent2 [1..5]
True
*Main> allDifferent2 [1..6]
False
*Main> allDifferent2 [1..7]
True
即。对于具有偶数元素的每个列表,它输出False,对于奇数量的元素,输出True。
我错过了什么? 有人会照顾一些光吗?
答案 0 :(得分:7)
另一种利用notElem
:
allDifferent :: (Eq a) => [a] -> Bool
allDifferent list = case list of
[] -> True
(x:xs) -> x `notElem` xs && allDifferent xs
次要变体,直接在方程中使用模式匹配:
allDifferent :: (Eq a) => [a] -> Bool
allDifferent [] = True
allDifferent (x:xs) = x `notElem` xs && allDifferent xs
我倾向于远离像head,tail
这样的部分功能,所以基于守卫的变种看起来更糟糕。
答案 1 :(得分:4)
我会这样做。递归+ elem
是 O(n²)。或者,您可以先对列表进行排序,然后成对比较元素。这样排序是 O(n⋅logn),遍历 O(n)。所以整体 O(n⋅logn):
import Data.List
allDifferent :: (Ord a, Eq a) => [a] -> Bool
allDifferent = comparePairwise.sort
comparePairwise :: Eq a => [a] -> Bool
comparePairwise [] = True
comparePairwise [_] = True
comparePairwise (x:y:xs)
| x == y = False
| otherwise = comparePairwise (y : xs)
答案 2 :(得分:1)
试试这个:
allDifferent2::(Eq a) => [a] -> Bool
allDifferent2 list
| list == [] = True
| (head list) `elem` (tail list) = False
| otherwise = allDifferent2(tail list)
如果列表为[],则应返回True(如@bheklilr所说:))
如果列表不为null,则可以验证第一个元素是否在列表的尾部。如果是,则返回False。好。
但是当你说“如果它在列表的尾部 OR allDifferent2(尾部列表)”时,你就是在杀死你的函数。 “如果此列表中的所有元素都不同,请返回 FALSE ”,这不是您想要的。
编辑:是的,它会@Luis。我通过把“否则”放在那里来解决这个问题。当我在allDifferent2(尾部列表)之前放置警卫时,它检查此函数是否返回True。因此它适用于[1,1,2](我的测试用例)但不适用于[1,2,2](与你的情况类似)。
答案 3 :(得分:1)
我能想到的最简单合理的惯用法是
import Data.Maybe
pairwiseDifferent xs = foldr go (const True) xs Nothing
where
go x k Nothing = k (Just x)
go x k (Just prev) = x /= prev && k (Just x)
有关折叠的乐趣,
Set
另一种选择是使用import qualified Data.Set as S
allDifferent xs = foldr go (\s -> s `seq` True) xs S.empty
where
go x k s
| S.member x s = False
| otherwise = k $! S.insert x s
(某些严格注释可能实际上不是必需的):
<html>
<head>
<title>Enormous Wedding III</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class = "container"><span>
<div id = "game"><iframe src='...'></div>
<div id = "video"><video autoplay> <source src="menu.mp4" type="video/mp4">
</video></div>
</span></div>
<script>
var video = document.getElementsByTagName('video')[0];
var game = document.getElementsByTagName('iframe')[0];
video.onended = function(e) {
video.style.display = "none";
};
</script>
</body></html>
答案 4 :(得分:1)
您可以依赖库函数:allDifferent xs = nub xs == xs
。
或者,用无点符号写成:allDifferent = uncurry (==) . (nub &&& id)
。
使用Data.Discrimination.nub,这发生在 O(n)时间。
答案 5 :(得分:1)
将列表,group
次相同元素的运行排序在一起,并检查all
组是否只有一个元素。
import Data.List (group, sort)
pairwiseDistinct :: Ord a => [a] -> Bool
pairwiseDistinct xs = all (\ys -> null (tail ys)) (group (sort xs))
无点版本:
pairwiseDistinct = all (null . tail) . group . sort
这假设任何两个元素x
和y
,x == y
当且仅当compare x y == EQ
。
tail
在这里没问题,因为没有一个组会变空,但如果你反对部分函数,你可以替换drop 1
。
答案 6 :(得分:0)
allDifferent [] = True
allDifferent (h:t) =
let (e,(l,r)) = segment h t
in e && allDifferent l && allDifferent r
segment p [] = (True,([],[])))
segment p (h:s)
| p > h = let (e,(l,r)) = segment p s in (e,(l,h:r))
| p < h = let (e,(l,r)) = segment p s in (e,(h:l,r))
| otherwise = (False,([],[])))
如您所见,此解决方案的结构与quickSort非常相似。 它共享一个二叉树作为中间数据结构,因此时间复杂度非常相似。