我最近选择了Haskell,我无法在代码中查看元素是否在(x:lx)
中列表的其余部分lx
。
我的代码:
atmostonce:: [Int] -> Int -> Bool
atmostonce [] y = True
atmostonce (x:lx) y
| (x==y) && (`lx` == y) = False
| otherwise = True
现在的方式是检查第一个元素(x==y)
,但我不知道如何检查y
中是否存在元素lx
。我实际想要完成的事情是找出在Intigers列表中lx
数字y
包含0或1次并返回True
否则返回False
< / p>
答案 0 :(得分:2)
您可以使用多种实现,我看到哪种实现避免将length
应用于潜在的无限列表
atmostonce xs y
= (<= 1)
$ length
$ take 2
$ filter (== y) xs
这会删除xs
中不等于y
的所有元素,然后最多取其中2个(take 2 [1] == [1]
,take 2 [] == []
),计算长度(它是这里使用安全,因为我们知道take 2
不会返回无限列表),然后检查是否不超过1.或者您可以使用直接递归来解决这个问题,但最好使用工作模式:
atmostonce = go 0
where
go 2 _ _ = False
go n [] _ = n <= 1
go n (x:xs) y =
if x == y
then go (n + 1) xs y
else go n xs y
n <= 1
子句可以替换为True
,但理想情况下,它会在n == 2
后短路,n
不应该是0以外的其他任何内容,1或2.但是,对于您的实现,我相信您正在寻找elem
函数:
elem :: Eq a => a -> [a] -> Bool
atmostonce [] y = True
atmostonce (x:ls) y
| (x == y) && (y `elem` ls) = False
| otherwise = True
但是这不会返回您想要的值,因为atmostonce [1, 2, 2, 2] 2
会返回True
。相反,如果x /= y
:
atmostonce (x:ls) y
| (x == y) && (y `elem` ls) = False
| otherwise = atmostonce ls y
答案 1 :(得分:1)
您可以使用elem
功能执行此操作:
atmostonce:: [Int] -> Int -> Bool
atmostonce [] y = True
atmostonce (x:lx) y | x /= y = atmostonce lx y
| otherwise = not $ elem y lx
您最好首先检查元素x
不是否等于y
。如果是这种情况,您只需调用递归部分atmostonce lx y
:然后在列表中进一步搜索。
如果是x == y
,(otherwise
情况),您需要检查lx
中是否有另一个元素(列表的其余部分),等于{{ 1}}。如果是这种情况,则需要返回x
,因为在这种情况下,列表中有多个实例。否则,您将返回False
。
此外,您可以进一步概括您的功能:
True
Eq
是一个类型类,它意味着在atmostonce:: (Eq a) => [a] -> a -> Bool
atmostonce [] y = True
atmostonce (x:lx) y | x /= y = atmostonce lx y
| otherwise = not $ elem y lx
上定义了函数==
和/=
。因此,无论a
(a
,Int
的实际类型如何,您都可以调用它们。
最后在第一种情况下,您可以使用下划线(String
),这意味着您不关心关于该值(尽管在这种情况下无关紧要)。您可以更改案例的顺序,因为它们是分离的,这使得函数在语法上 total :
_
答案 2 :(得分:1)
现有答案很好,但您可以使用dropWhile
执行当前通过手动递归完成的部分:
atMostOnce xs y =
let afterFirstY = drop 1 $ dropWhile (/= y) xs
in y `notElem` afterFirstY