如何在 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
只保留第一个元素是 l2
的 elem
ent 的那些对。
过滤谓词(\(c,_) -> c `elem` l2)
也可以写成((`elem` l2) . fst)
.
关于性能,如果 l2
和 l1
相对于 fst
排序的事实只是一个信心问题或对示例的过度简化,我们可以观察到 filter
ing 是一个线性运算,因为你必须遍历 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"]
基本上我想做的是:给定一个由元组 [(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
只保留第一个元素是 l2
的 elem
ent 的那些对。
过滤谓词(\(c,_) -> c `elem` l2)
也可以写成((`elem` l2) . fst)
.
关于性能,如果 l2
和 l1
相对于 fst
排序的事实只是一个信心问题或对示例的过度简化,我们可以观察到 filter
ing 是一个线性运算,因为你必须遍历 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"]