交换Haskell中的列表列表

时间:2013-01-06 20:30:43

标签: list haskell fold interleave

我想知道如何在Haskell中编写一个将列表列表交织到单个列表中的函数,例如,如果我有一个名为

的函数

interleavelists :: [[a]] -> [a]

它应该能够交错元素。

示例:[[1,2,3] [4,5,6] [7,8]] --> [1,4,7,2,5,8,3,6]

列表可以是有限的也可以是无限的......我可以使用foldr吗?

4 个答案:

答案 0 :(得分:25)

编写它的最快方法是使用Data.List中的transpose

import Data.List

interleavelists :: [[a]] -> [a]
interleavelists = concat . transpose

transpose选择其参数的每个非空列表的第一个元素,将它们放入一个列表中,然后transpose列出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

这不是很漂亮,如果列表不是全部相同的长度将产生可能不是所需的输出。但是如果列表都具有相同的长度,它就可以完成工作。

答案 1 :(得分:4)

简单的递归版本:

inter :: [[a]] -> [a]
inter [] = []
inter xs = inter2 (filter (\x -> not (null x)) xs)
   where inter2 xs = map head xs ++ inter (map tail xs)

现在,关于折叠...

答案 2 :(得分:2)

在SICP(以及后来的推理方案)的欢乐时代,“标准”(或许是着名的)交错列表的方式是

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]

这显然不会按照你想要的顺序产生结果,但是当列表的输入列表是无限的时候OTOH会工作正常。我认为没有办法同时满足这两个要求,因为我们无法知道输入列表是否是无限的。

以上结果是来自Daniel's answerinsertAtDistance函数产生的结果,如果修改为始终以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]

答案 3 :(得分:1)

我们可以做你想做的事情

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]] =&gt; [1,4,7,2,5,8,3,6]