我在尝试分离列表时遇到问题,假设我们有以下列表
[[1,2,3,4], [5,6,7,8], [9,10,11,12 ], [13,14,15,16,17]].
结果应为:
[[1,5,9,13] [2,6,10,14] [3,7,11,16] [4,8,12,16]]
我试图按照以下方式进行:
joinHead (x: xs) = map head (x: xs)
separateLists (x: xs) = xs joinHead x ++ separateLists
显然这不起作用。我希望你能帮助我。 THX。
答案 0 :(得分:0)
我调整了您编写的函数joinHead
和separateLists
,以使代码工作,同时保留您所遵循的逻辑。从我可以推断出这些函数的推断,我们的想法是使用joinHead
来提取每个子列表的第一个元素并返回一个新列表。然后,这个新列表应该插入到递归调用separateLists
返回的列表列表的前面。
以下是joinHead
的新定义:
joinHead :: [[a]] -> [a]
joinHead ([]:_) = []
joinHead xs = map head xs
请注意,第一行通过模式匹配检查列表列表中包含的第一个列表是否为空,如果是,则返回空列表([]
)。原因是两个:
head
不安全。这意味着在空列表上调用head
将导致抛出异常(尝试在GHCi head []
中运行); length (xs !! 0) == length (xs !! 1) ...
)。 separateLists
的定义如下:
separateLists :: [[a]] -> [[a]]
separateLists ([]:_) = []
separateLists ([x]:xs) = [joinHead ([x]:xs)]
separateLists xs = joinHead xs : separateLists (map tail xs)
同样,前两个定义对于停止递归和安全目的都是必要的。第一行说:“如果第一个列表为空,则所有列表的所有元素都已消耗,因此返回[]
”。第二行说:“如果第一行只有一个元素,那么只需调用joinHead
并返回包含在列表中的结果”。请注意,在第三个定义中,我们调用了tail
,与head
一样,在[]
上调用时会抛出异常。这就是为什么我们需要一个长度为1的列表的单独案例的原因。最后,为长度大于1的列表执行的第三行从joinHead xs
获取一个列表并插入它(使用“缺点”在递归调用(:)
返回的列表开头的“operator separateLists
”。在此次调用中,我们必须删除所有列表中的第一个元素,这就是我们使用map tail xs
的原因。
现在,运行:
λ: let list = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16,17]]
λ: separateLists list
[[1,5,9,13],[2,6,10,14],[3,7,11,15],[4,8,12,16]]
会给你预期的结果。我希望它足够清楚。最后,我想指出这个实现远非最佳,并且正如评论中所建议的那样,您应该使用标准Data.List.transpose
。作为一个运动和didatic的例子,它很好! ; - )