在列表中查找对
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在列表中查找对相关的知识,希望对你有一定的参考价值。
我试图在列表中查找元素对,假设它们是列表中的唯一对,并且不超过3个相同的连续元素。
我有一个函数,它接受一个列表,并返回该对的第一个元素的索引,如果有的话。如果没有,则返回-1
searchForPairs xs = searchHelp xs ((genericLength xs) - 1)
where searchHelp xs n
| searchHelp xs 0 = -1 -- no pairs found
| (xs !! n) == (xs !! (n - 1)) = n
| otherwise = searchHelp xs n-1
出于某种原因,它返回错误:
Couldn't match expected type `Bool' with actual type `Int'
In the expression: n
In an equation for `searchHelp':
searchHelp xs n
| searchHelp xs 0 = - 1
| (xs !! n) == (xs !! (n - 1)) = n
| otherwise = searchHelp xs n - 1
In an equation for `searchForPairs':
searchForPairs xs
= searchHelp xs ((genericLength xs) - 1)
where
searchHelp xs n
| searchHelp xs 0 = - 1
| (xs !! n) == (xs !! (n - 1)) = n
| otherwise = searchHelp xs n - 1
它似乎应该工作。任何想法为什么不是?
@gereeter已经解释了你的错误,我只想指出你不应该返回-1
以防万一找不到答案。相反,如果没有答案,你应该返回Nothing
,如果答案是Just pos
,你应该返回pos
。这可以保护您免受各种错误的影响。
我无法理解你想做什么,但是从代码中看,你似乎想要在列表中找到两个相同的连续元素。您可以使用模式匹配来提取列表的前两个元素,检查它们是否相等,并继续搜索其余部分(包括第二个元素),而不是使用!!
索引列表。如果列表没有至少两个元素,则返回Nothing
searchForPairs xs = go 0 xs where
go i (x1:xs@(x2:_)) | x1 == x2 = Just i
| otherwise = go (i+1) xs
go _ _ = Nothing
你有两个问题。第一个是这一行:
| otherwise = searchHelp xs n-1
编译器将此作为(searchHelp xs n) - 1
,而不是searchHelp xs (n-1)
,如您所愿。第二个问题是你使用警卫:
| searchHelp xs 0 = -1 -- no pairs found
由于searchHelp xs 0
不是布尔表达式(您希望将其用作模式),因此编译器拒绝了它。我可以看到两个简单的解决方案
searchForPairs xs = searchHelp xs ((genericLength xs) - 1)
where searchHelp xs n
| n == 0 = -1 -- no pairs found
| (xs !! n) == (xs !! (n - 1)) = n
| otherwise = searchHelp xs (n-1)
和
searchForPairs xs = searchHelp xs ((genericLength xs) - 1)
where
searchHelp xs 0 = -1 -- no pairs found
searchHelp xs n
| (xs !! n) == (xs !! (n - 1)) = n
| otherwise = searchHelp xs (n-1)
现在,不幸的是,虽然这有效,但效率非常低。这是因为你使用了!!
。在Haskell中,列表是链表,因此xs !! n
将采用n步,而不是1.这意味着函数所用的时间是列表长度的二次方。要解决此问题,您需要使用模式匹配向前循环列表:
searchForPairs xs = searchHelp xs 0 where
searchHelp (x1 : x2 : xs) pos
| x1 == x2 = pos
| otherwise = searchHelp (x2 : xs) (pos + 1)
searchHelp _ _ = -1
对于它的价值,这是一个有点惯用(和无点)实现你想要做的事情:
searchPairs :: Eq a => [a] -> Maybe Int
searchPairs = interpret . span (uncurry (/=)) . (zip <*> tail)
where
interpret (flag, res) = if null flag then Nothing else Just $ length res
说明:zip <*> tail
创建一系列连续元素的列表(使用reader Applicative类型)。 uncurry (/=)
测试这样的一对是否由相同的元素组成。最后,interpret
将结果转换为Maybe Int
类型的值。
以上是关于在列表中查找对的主要内容,如果未能解决你的问题,请参考以下文章