用 Haskell 合并两个嵌套列表的元素
Merging the elements of two nested lists with Haskell
我想在一个列表中附加列表,在第二个列表中附加列表。
使用 concat
创建所有元素的一个列表,而 zip
似乎将两个嵌套列表组合成一个嵌套列表而不组合子列表。
let x = [["one", "two"],["five", "six"], ["nine", "ten"]]
let y = [["three", "four"],["seven", "eight"], ["eleven", "twelve"]]
应该变成
[["one", "two", "three", "four"], ["five", "six", "seven", "eight"], ["nine", "ten", "eleven", "twelve"]]
如何实现上述结果?我的直觉是使用 map
虽然我一直没有成功。
在某些语言中,如 Scheme map
可以接受任意数量的列表,但在 Haskell 中,二进制 map
有自己的名称,zipWith
:
zipWith (++) x y
会做你想做的。
如何到达那里,在 REPL 玩:
> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
-- BTW these are not lists, but tuples
> zipWith (,) x y -- same thing as zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> zipWith (\a b -> (a,b)) x y -- same thing as the above
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> zipWith (\a b -> [a,b]) x y -- not the same thing as the above
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]
> zipWith (\a b -> concat [a,b]) x y -- success!
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
> zipWith (\a b -> a ++ b) x y -- equivalent to the above
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
> zipWith (++) x y -- finally, simplified.
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
但是您可以也可以根据需要使用map
来处理zip
的输出:
> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> map id $ zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> map (\(a,b) -> a ++ b) $ zip x y -- the same as zipWith (++)
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
实现此目的的另一种方法是使用 transpose
,它本身就是一种 zip
:
map concat $ transpose [x,y]
这使用与我们在上面看到的相同的 concat
两个列表,现在可以处理任意数量的子列表,每个子列表都来自原始列表(这里仍然是两个):
> transpose [x,y]
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]
因此它可以毫不费力地扩展到处理任意数量的列表:
map concat $ transpose [x,y,z]
等等