简体   繁体   English

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

[英]Apply a function to every element in a list to every element in another list - Haskell

My ultimate goal is to find if a list y contains all the elements of list x (I'm checking if x is a subset of y sort of thing) 我的最终目标是确定列表y是否包含列表x的所有元素(我正在检查x是否是y的子集)

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

This doesn't work, and I know it's because z is a list still. 这不起作用,我知道这是因为z仍然是列表。 I'm trying to make sense of this. 我试图弄明白这一点。

I think I may have to use the elem function, but I'm not sure how to split x into chars that I can compare separately through y. 我想我可能必须使用elem函数,但是我不确定如何将x拆分为可以通过y分别比较的字符。

I'm ashamed to say that I've been working on this simple problem for an hour and a half. 我很to愧地说我已经在这个简单的问题上工作了一个半小时。

Checking whether all elements of xs are elements of ys is very straightforward. 检查xs所有元素是否都是ys元素非常简单。 Loop through xs , and for each element, check if it is in ys : 遍历xs ,对于每个元素,检查它是否在ys

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

You could also use the list difference function ( \\\\ ). 您还可以使用列表差异功能( \\\\ )。 If you have list y and list x, and you want to check that all elements of x are in y, then x \\\\ y will return a new list with the elements of x that are not in y. 如果您具有列表y和列表x,并且要检查x的所有元素都在y中,则x \\\\ y将返回一个新列表,其中包含x的元素不在y中。 If all the elements of x are in y, the returned list will be empty. 如果x的所有元素都在y中,则返回的列表将为空。

For example, if your list y is [1,2,3,4,5] and your list x is [2,4], you can do: 例如,如果列表y为[1,2,3,4,5],列表x为[2,4],则可以执行以下操作:

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

If list y is [1,2,3,4,5] and list x is [2,4,6], then: 如果列表y为[1,2,3,4,5],列表x为[2,4,6],则:

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

Easy way to reason about subsets is to use sets as the data type. 推断子集的简单方法是使用集合作为数据类型。

import qualified Data.Set as S

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

Then it's as simple as: 然后就这么简单:

*Main> subset [1..5] [1..10]
True
*Main> subset [0..5] [1..10]
False

Let's break this down into two subproblems: 让我们将其分解为两个子问题:

  1. Find if a value is a member of a list; 查找是否为列表的成员;
  2. Use the solution to #1 to test whether every value in a list is in the second one. 使用#1的解决方案来测试列表中的每个值是否在第二个值中。

For the first subproblem there is a library function already: 对于第一个子问题,已经有一个库函数:

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

Lists are a Foldable type, so you can use this function with lists for t and it would have the following type: 列表是Foldable类型,因此您可以将此函数与t列表一起使用,并且它将具有以下类型:

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

EXERCISE: Write your own version of elem , specialized to work with lists (don't worry about the Foldable stuff now). 练习:编写自己的elem版本,专门用于处理列表(现在不用担心Foldable东西)。

So now, to tackle #2, one first step would be this: 所以现在,要解决第二个问题,第一步就是:

-- 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

After that, we need to go from the list of individual boolean results to just one boolean. 之后,我们需要从单个布尔结果列表中删除一个布尔值。 There's a standard library function that does that as well: 有一个标准的库函数也可以做到这一点:

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

EXERCISE: write your own version of and , specialized to lists: 锻炼:编写自己的and版本,专门用于列出:

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

With these tools, now we can write subset : 使用这些工具,现在我们可以编写subset

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

Although a more experienced Haskeller would probably write it like this: 尽管经验丰富的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
-}

...where every is another standard library function that is just a shortcut for the combination of map and and : ...其中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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将函数应用于Haskell列表中的每个元素? - how to apply function to every element in a list in Haskell? 将函数应用于列表中的每个元素到另一个列表中的每个元素 - Apply a function to every element in a list to every element in another list 将 Function 应用于列表中的每个元素 - Apply a Function to every element in a list 如何将 mod 应用于 Haskell 列表中的每个元素 - How to apply mod to every element in a list in Haskell 将两个输入的函数应用于列表中的每个元素 - Haskell - Apply a function of two inputs to every element in a list - Haskell Haskell函数用于交换列表中的每个第二个元素 - Haskell function to swap every second element in a list 如何在haskell中将列表中的每个元素与另一个列表中的每个元素相除 - How to divide every element in a list with each element in another list in haskell 将函数应用于列表中的每个第二个元素 - Apply a function to every second element in a list 在haskell中切换列表中的每个元素 - Toggle every element in a list in haskell 在Haskell中是否可以将putStrLn函数应用于字符串列表的每个元素,使其打印到屏幕上,而无需递归 - Is it possible in Haskell to apply the function putStrLn to every element of a list of Strings, have it print to the screen, while being non recursive
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM