如何从两个列表和这些列表中的元素交替创建列表

时间:2017-01-22 15:14:42

标签: haskell recursion

我是Haskell的新手。我正在尝试使用递归来编写一个函数,给定两个列表(它们需要是相同的类型),交织它们的元素(在第一个和第二个列表之间交替使用元素)。当其中一个列表中没有其他元素时,它会停止,结果就是到目前为止所实现的列表。

interChange :: [a] -> [b] ->[(a,b)]
interChange _ [] = []
interChange [] _ = []
interChange (x:xs) (y:ys) =  (x,y) : interChange xs ys

我的输出示例:

interChange [1,2,3] [4,5,6]
 [(1,4),(2,5),(3,6)]

所需输出的示例是:

interChange [1,2,3] [4,5,6]
[1,4,2,5,3,6]

感谢您的帮助

2 个答案:

答案 0 :(得分:3)

您的interleave :: [a] -> [a] -> [a] 与Prelude的source相同。

Bool

要编写您指定的函数,您实际上需要一对相同类型的列表。我们输出的是特定类型的列表,因此进入该列表的所有元素也必须具有该类型。

interleave = go True
    where go _ [] ys = ys
          go _ xs [] = xs
          go True (x:xs) ys = x : go False xs ys
          go False xs (y:ys) = y : go True xs ys

您可以通过传递go以递归的方式实现此目的,指示您应该从哪个列表中获取下一个元素:

zip

评估[]的最后两个子句之间的ping-pongs,直到其中一个输入列表为空,然后我们只返回另一个的其余部分。 (如果您希望它的行为更像xs,则可以通过在这些情况下返回ys而不是zipmap (\(x, y) -> [x, y])来截断输出。)

但我总是建议尽可能避免递归到更高级别的编程。我们可以将此函数编写为管道:

  1. 使用concat
  2. 配置输入列表的元素
  3. 将结果列表中的每个元组转换为一个双元素列表:interleave xs ys = concat $ map (\(x, y) -> [x, y]) $ zip xs ys
  4. 使用map
  5. 展平生成的列表列表

    所以代码看起来像这样:

    concat

    我觉得这个代码比递归代码更容易理解,它需要你推理控制流 - 它只是一系列高级指令。

    顺便提一下,您可以将中间版zip拖入interleave xs ys = concatMap (\(x, y) -> [x, y]) $ zip xs ys interleave xs ys = concat $ zipWith (\(x, y) -> [x, y]) xs ys SELECT Student_Name AS StudentName,count(Student_Name) Total FROM Student_Table GROUP BY Student_Name`

    {{1}}

答案 1 :(得分:2)

当使用两个非空列表interChange(x:xs)调用(y:ys)时,输出应该是以x开头,然后是y的列表,然后是更多东西。所以你应该写点像

interChange (x:xs) (y:ys) =  x : y : ...