如何在 Haskell 中同时遍历两个列表?

How do I iterate through two lists simultaneously in Haskell?

基本上我想做的是:给定一个由元组 [(x,[y])] 和另一个字符串列表 [a] 组成的列表,我想创建一个包含所有 [y]'s where x == a 如果这是有道理的,所以如果我有 [('a', ['z', 'k', 'x']), ('b', ['z']), ('c', ['y', 'j'])]['a', 'c'],当两个列表都通过函数传递时结果列表将是 [['z', 'k', 'x'], ['y', 'j']].

我想出的解决方案有点荒谬而且过于复杂,(以及非功能性的)但只是为了让你看到我一直在考虑什么样的路径我会 post 它在下面。

foo ys xs acc = map (\x -> (map (\(a,y) -> if x == a then y:acc else []) ys)) xs

这打印了我想要的内容,但也打印了大量额外的括号,这使得输出非常混乱,毫无疑问,因为我把 map 函数混为一谈了。有什么建议吗?

给定

l1 = [('a', ['z', 'k', 'x']), ('b', ['z']), ('c', ['y', 'j'])]
l2 = ['a', 'c']

一个快速直观的解决方案是

filter (\(c,_) -> c `elem` l2) l1

哪个过滤器 l1 只保留第一个元素是 l2element 的那些对。

过滤谓词(\(c,_) -> c `elem` l2)也可以写成((`elem` l2) . fst).


关于性能,如果 l2l1 相对于 fst 排序的事实只是一个信心问题或对示例的过度简化,我们可以观察到 filtering 是一个线性运算,因为你必须遍历 l1 的所有元素来决定是否每个元素都必须保留或过滤掉。但也许 `elem` l2 操作的查找可以通过使 l2 成为 Set 来改进,只需将 `elem` l2 更改为 `elem` Data.Set.fromList l2.

相反,如果列表确实如示例中那样排序,则其他方法也是可能的。举个例子,如果 l1 和上面一样,但是 l2['d', {-whatever-}],那么你就知道输出是空的。

假设这两个列表已排序,就像在您的示例中一样,那么您可以使用 pattern-matching 和 guards:

同时遍历这两个列表
foo ((x,y):xs) (z:zs) | x == z =
foo ((x,_):xs) (z:zs) | x < z =
foo ((x,y):xs) (z:zs) | x > z =
foo [] _ =
foo _ [] =

我特意将 = 符号后的所有内容都留空了,因为我相信如果你自己填写它,你会比我丢掉一个解决方案学到更多。尽管我确实留下了一个小提示,在需要的地方包含了 y,在不需要的地方包含了 _

测试:

ghci> foo [('a', ['z', 'k', 'x']), ('b', ['z']), ('c', ['y', 'j'])] ['a', 'c']
["zkx","yj"]