将函数应用于列表中的每个元素到另一个列表中的每个元素 - Haskell

时间:2016-02-07 00:08:44

标签: haskell ghci

我的最终目标是查找列表y是否包含列表x的所有元素(我检查x是否是y类型的子集)

subset x y =
and [out | z <- x
         , out <- filter (==z) y ]

这不起作用,我知道这是因为z仍然是一个列表。我试图理解这一点。

我想我可能不得不使用elem函数,但我不确定如何将x拆分为可以通过y单独比较的字符。

我很惭愧地说我已经在这个简单的问题上工作了一个半小时。

4 个答案:

答案 0 :(得分:3)

检查xs的所有元素是ys的元素是非常简单的。循环遍历xs,并为每个元素检查它是否在ys

subset xs ys = all (\x -> elem x ys) xs

答案 1 :(得分:1)

您还可以使用列表差异功能(\\)。如果你有列表y和列表x,并且你想要检查x的所有元素都在y中,那么x \\ y将返回一个新的列表,其中x的元素不在y中。如果x的所有元素都在y中,则返回的列表将为空。

例如,如果您的列表y为[1,2,3,4,5]且列表x为[2,4],则可以执行以下操作:

Prelude> [2,4] \\ [1,2,3,4,5]
[]

如果列表y是[1,2,3,4,5]而列表x是[2,4,6],那么:

Prelude> [2,4,6] \\ [1,2,3,4,5]
[6]

答案 2 :(得分:0)

推理子集的简单方法是使用集合作为数据类型。

import qualified Data.Set as S

subset :: Ord a => [a] -> [a] -> Bool
subset xs ys = S.isSubsetOf (S.fromList xs) (S.fromList ys)

然后它就像:

一样简单
*Main> subset [1..5] [1..10]
True
*Main> subset [0..5] [1..10]
False

答案 3 :(得分:0)

让我们将其分解为两个子问题:

  1. 查找是否为列表成员;
  2. 使用#1的解决方案来测试列表中的每个值是否在第二个。
  3. 对于第一个子问题,已经有一个库函数:

    elem :: (Eq a, Foldable t) => a -> t a -> Bool
    

    列表是Foldable类型,因此您可以将此函数与t的列表一起使用,它将具有以下类型:

    elem :: (Eq a) => a -> [a] -> Bool
    

    练习:编写您自己的elem版本,专门用于处理列表(现在不用担心Foldable内容。)

    现在,要解决#2问题,第一步就是:

    -- For each element of `xs`, test whether it's an element of `ys`.
    -- Return a list of the results.
    notYetSubset :: Eq a => [a] -> [a] -> [Bool]
    notYetSubset xs ys = map (\x -> elem x ys) xs
    

    之后,我们需要从单个布尔结果列表转到一个布尔值。还有一个标准的库函数也能做到这一点:

    -- Return true if and only if every element of the argument collection is 
    -- is true.
    and :: Foldable t => t Bool -> Bool
    

    练习:编写您自己的and版本,专门用于列表:

    myAnd :: [Bool] -> Bool
    myAnd [] = _fillMeIn
    myAnd (x:xs) = _fillMeIn
    

    使用这些工具,现在我们可以编写subset

    subset :: Eq a => [a] -> [a] -> [Bool]
    subset xs ys = and (map (\x -> elem x ys) xs)
    

    虽然经验丰富的Haskeller可能会这样写:

    subset :: Eq a => [a] -> [a] -> [Bool]
    subset xs ys = every (`elem` ys) xs
    
    {- This:
    
           (`elem` ys)
    
       ...is a syntactic shortcut for this:
    
           \x -> x elem ys
    -}
    

    ...其中every是另一个标准库函数,它只是mapand组合的快捷方式:

    -- Apply a boolean test to every element of the list, and
    -- return `True` if and only if the test succeeds for all elements.
    every :: (a -> Bool) -> [a] -> Bool
    every p = and . map p