检查列表其余部分中的元素(lx)

时间:2015-03-26 15:18:54

标签: haskell

我最近选择了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>

3 个答案:

答案 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 上定义了函数==/=。因此,无论aaInt的实际类型如何,您都可以调用它们。

最后在第一种情况下,您可以使用下划线(String),这意味着您不关心关于该值(尽管在这种情况下无关紧要)。您可以更改案例的顺序,因为它们是分离的,这使得函数在语法上 total

_

答案 2 :(得分:1)

现有答案很好,但您可以使用dropWhile执行当前通过手动递归完成的部分:

atMostOnce xs y =
    let afterFirstY = drop 1 $ dropWhile (/= y) xs
    in y `notElem` afterFirstY