获取循环列表的第一个重复元素

时间:2018-12-12 01:12:05

标签: haskell lazy-evaluation

我正在尝试从循环列表中获取第一个重复元素。例如

[1,-2, 3, 2, 3, 4, 5, 5]     => Just 3
[0,-2, 9, 2, 3, 4, -23,- 2] => Just (-2)

v1:

firstDup :: Ord a => [a] -> Maybe a
firstDup [] = Nothing
firstDup (x:xs)
  | [x] `intersect` xs == [x]   =  Just x
  | otherwise         = firstDup xs

v2:

firstDup' :: Ord a => [a] -> Maybe a
firstDup' = go Set.empty
  where
    go _ [] = Nothing
    go z (x:xs)
      | x `Set.member` z = Just x
      | otherwise        = go (Set.insert x z) xs

我希望v1和v2产生相同的结果,但是它们不会。

firstDup       . cycle       $ [1,-2, 3, 2, 3, 4, 5, 5]  ==> Just 1
firstDup'      . cycle       $ [1,-2, 3, 2, 3, 4, 5, 5]  ==> Just 3

我想知道为什么v1和v2会产生不同的结果。

2 个答案:

答案 0 :(得分:5)

请注意谓词

[x] `intersect` xs == [x]

始终为 true ,因为cycle将列表无限重复为

[1, -2, 3, 2, 3, 4, 5, 5, 1, -2, 3, 2, 3, 4, 5, 5, ...]

1必须是[-2, 3, 2, 3, 4, 5, 5, 1, -2, 3, 2, 3, 4, 5, 5, ...]的元素

如此

[1] `intersect` [-2, 3, 2, 3, 4, 5, 5, 1, -2, 3, 2, 3, 4, 5, 5, ...] = [1]

这就是V1 firstDup返回Just 1的原因。

V2中,firstDup'递归构造一个Set:

{}
{1}
{1, -2}
{1, -2, 3}
{1, -2, 3, 2, ...}

并检查下一个插入的元素是否为Set as的元素

1  `Set.member` {}
-2 `Set.member` {1}
3  `Set.member` {1, -2}
2  `Set.member` {1, -2, 3}
3  `Set.member` {1, -2, 3, 2}

请注意,3{1, -2, 3, 2}的成员,因此firstDup'返回Just 3

答案 1 :(得分:3)

v1中,它返回列表中第一个元素重复出现在其自身位置的第一个元素。

v2中,它返回列表中第一个在其自身的某处重复的元素。

在循环列表中,第一个元素将始终在右侧某处重复,因此v1将始终返回第一个元素。同时,v2等到之前已经看到一个元素。