我想知道如何在 Haskell 中编写一个将列表列表交错为单个列表的函数,例如,如果我有一个名为的函数
interleavelists :: [[a]] -> [a]
它应该能够交错元素。
示例:[[1,2,3] [4,5,6] [7,8]] --> [1,4,7,2,5,8,3,6]
。
列表可以是有限的也可以是无限的......我可以使用foldr
吗?
我想知道如何在 Haskell 中编写一个将列表列表交错为单个列表的函数,例如,如果我有一个名为的函数
interleavelists :: [[a]] -> [a]
它应该能够交错元素。
示例:[[1,2,3] [4,5,6] [7,8]] --> [1,4,7,2,5,8,3,6]
。
列表可以是有限的也可以是无限的......我可以使用foldr
吗?
最快的编写方法是使用transpose
from Data.List
。
import Data.List
interleavelists :: [[a]] -> [a]
interleavelists = concat . transpose
transpose
选择其参数的每个非空列表的第一个元素,将它们放入一个列表中,然后是参数元素的transpose
s 列表。生成的结果列表会根据需要交错列表。如果某些元素列表是无限的,它会起作用,但如果列表列表本身有无限多的元素,它当然永远不会超过s 的列表。但无论如何处理这种情况是有问题的。tail
concat
transpose
head
使用foldr
交错列表并非易事。假设你有
interleavelists xss = foldr something zero xss
interleavelists []
应该可能产生[]
,所以这就是zero
价值。和
interleavelists [xs] = xs
看起来很自然,所以
something xs [] = xs
但是如果第二个参数不是[]
呢?然后你想将第一个参数的元素something
以不同的距离插入到第二个参数中。但在哪些距离?如果所有列表的长度相同,则每个列表的距离都是恒定的,那么您可以将距离作为进一步的参数传递,
interleavelists = snd . foldr insertAtDistance (0, [])
where
insertAtDistance xs (d, ys) = (d+1, helper d xs ys)
helper _ [] ws = ws
helper k (b:bs) cs = b : us ++ helper k bs vs
where
(us,vs) = splitAt k cs
这不是很漂亮,如果列表的长度不同,将产生可能不是所需的输出。但是,如果列表都具有相同的长度,它就可以完成工作。
简单的递归版本:
inter :: [[a]] -> [a]
inter [] = []
inter xs = inter2 (filter (\x -> not (null x)) xs)
where inter2 xs = map head xs ++ inter (map tail xs)
现在,关于文件夹...
交错列表的“标准”(或者也许是著名的)方式,早在 SICP(以及后来的 Reasoned Scheme)的快乐日子里,是
infixr 5 ++/
[] ++/ ys = ys
(x:xs) ++/ ys = x:(ys ++/ xs)
它可以与foldr
,
*Main> foldr (++/) [] [[1,2,3],[4,5,6],[7,8]]
[1,4,2,7,3,5,8,6]
这显然不会按照您想要的顺序产生结果,但是当列表的输入列表是无限的时,它会正常工作。我认为没有办法同时满足这两个要求,因为我们无法知道输入列表是否是无限的。
上面的结果是丹尼尔答案中的函数insertAtDistance
将产生的结果,如果修改为始终插入距离为1
,而不是d+1
:
insertAtDistance xs (d, ys) = (1, helper d xs ys)
当用d+1
它定义时,会产生“扁平”交织,而foldr (++/) []
产生倾斜交织:
*Main> take 20 $ foldr (++/) [] [cycle[i] | i<-[1..]]
[1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3]
我们可以做你想做的
testList = [[1,2,3],[4,5,6],[7,8]]
interleave l = foldr' (concat [map (\x -> f x idx) l | idx <- [0..]])
where
f x n = if (length(x)<=n) then Nothing else Just (x !! n)
foldr' (x:xs) = case x of
Nothing -> []
Just a -> (:) a (foldr' xs)
根据需要交错 [[1,2,3] [4,5,6] [7,8]] => [1, 4, 7, 2, 5, 8, 3, 6]