Ekn*_*oma 2 indexing haskell concatenation
我正在寻找一种将列表列表与单个列表合并的方法,以保持列表列表的结构。即函数 foo 的工作方式如下:
foo :: [[a]] -> [b] -> [[(a,b)]]
> foo [[1],[2,2,3],[7,8]] [0..]
[[(1,0)],[(2,1),(2,2),(3,3)],[(7,4),(8,5)]]
Run Code Online (Sandbox Code Playgroud)
(或者反过来说)
foo :: [b] -> [[a]] -> [[(b,a)]]
> foo [0..] [[1],[2,2,3],[7,8]]
[[(0,1)],[(1,2),(2,2),(3,3)],[(4,7),(5,8)]]
Run Code Online (Sandbox Code Playgroud)
当然,如果我们知道每个列表的长度相等,则可以通过以下方式轻松创建此函数:
import Data.List.Split (chunksOf)
foo :: [[a]] -> [b] -> [[(a,b)]]
foo xs ys = chunksOf n $ zip (concat xs) ys
where
n = length $ head xs
Run Code Online (Sandbox Code Playgroud)
但是,在列表长度不等的更一般情况下,如何完成此功能呢?
您可以使用嵌套遍历:遍历外部列表,遍历每个内部列表,并在每一步弹出另一个列表的元素并将其与当前遍历的元素配对。这可以很好地写在状态单子中:
\nimport Control.Monad.Trans.State\n\nfoo :: \xe2\x88\x80 a b . [[a]] -> [b] -> [[(a,b)]]\nfoo ls ys = evalState nestedTrav ys\n where nestedTrav :: State [b] [[(a,b)]]\n nestedTrav = forM ls $ \\l ->\n forM l $ \\x ->\n state $ \\(y:ys) -> (ys, (x,y))\nRun Code Online (Sandbox Code Playgroud)\n...或更短
\nfoo ls ys = (`evalState`ys)\n . forM ls . traverse\n $ \\x -> state $ \\(y:ys) -> (ys, (x,y))\nRun Code Online (Sandbox Code Playgroud)\n仅当第二个列表至少与所有第一个列表一样长(或无限,如您的示例中)时,这才有效。我建议您通过将遍历版本分解为折叠和/或递归来实现一般情况,然后在第二个列表变空时添加中止机制。
\n