我只是从Haskell开始,我不确定如何执行此操作,但是当我输入[1,2,3,4] [5,6,7,8,9,10,11 ,12]输出应为[[(1,5),(2,6),(3,7),(4,8)] [(1,9),(2,10),(3,11 ),(4,12)]]。我试图做某事,请参阅下面的代码。但这仅适用于特定大小的列表。我确信必须有一种方法可以更有效地执行此操作,并且对于任何大小的递归列表,有人可以帮助我吗?
splitlist :: [a] -> [b] -> [[(a,b)]]
splitlist list1 list2 = [a,b,c] where
n = length list1
a = zip list1 list2
nlist = drop n list2
b = zip list1 nlist
nnlist = drop n nlist
c = zip list1 nnlist
答案 0 :(得分:2)
第一个列表中两个列表中的最长列表时,first answer不起作用; second answer对于这样一个简单的任务来说似乎太长了。
修改第一个答案的代码很容易,
$tid
在两种情况下都可以使用,也可以使用无限列表。
答案 1 :(得分:1)
一个有趣的问题! cycle
在这种情况下可能会有所帮助,它会重复列出无限时间的元素,例如
cycle [1,2,3,4] = [1,2,3,4,1,2,3,4,1,....]
因此,何时使用[5,6,7,8,9,10,11,12]
进行压缩将是理想的结果[(1,5),(2,6),(3,7),(4,8),(1,9),(2,10),(3,11),(4,12)]
,然后使用chunksOf
(在Data.List.Split中定义)将其分组为[[(a, b)]]
类型为:
splitList::[a]->[b]->[[(a,b)]]
splitList [] _ = []
splitList _ [] = []
splitList list1 list2
| length list1 <= length list2 = doSplit (length list1) (cycle list1) list2
| otherwise = doSplit (length list2) list1 (cycle list2)
where doSplit len xs ys = chunksOf len $ zip xs ys
P.S此解决方案仅适用于有限列表
答案 2 :(得分:1)
另一个答案显示了如何重用库函数。但是,它有一个小缺陷:它会在开始返回结果之前将其参数强制存储到内存中,因此它无法与Haskell其余的惰性基础结构完美地配合使用。在这个答案中,我将展示如何编写一个版本:
我们将构建其他答案中使用的所有片段,但将其简化版本:我们将隐式地使用类型为Int
的列表,而不是使用[a]
作为长度代表自己的长度。我们需要的第一件事是比较两个惰性数字。稍后会发现,让我们的比较返回不仅是哪个数字更大,而且两个数字的差也很方便。
data LazyOrdering a b
= LazyLT [b]
| LazyEQ
| LazyGT [a]
deriving (Eq, Ord, Read, Show)
lazyCompare :: [a] -> [b] -> LazyOrdering a b
lazyCompare [] [] = LazyEQ
lazyCompare [] bs = LazyLT bs
lazyCompare as [] = LazyGT as
lazyCompare (ah:at) (bh:bt) = lazyCompare at bt
接下来,我们需要chunksOf
;我们将以splitAt
的简化版本来实现它。后者应采用“惰性”长度来分割其列表参数。我们非常小心地尽快开始生成元素-也就是说,一旦我们知道要拆分的索引大于0并且要拆分的列表是非空的,就可以了。
lazySplitAt :: [a] -> [b] -> ([b], [b])
lazySplitAt [] bs = ([], bs)
lazySplitAt _ [] = ([], [])
lazySplitAt (_:as) (b:bs) = (b:bb, be) where ~(bb, be) = lazySplitAt as bs
我们的惰性chunksOf
变体现在可以将lazySplitAt
用作子例程。同样,我们将“惰性”数字作为第一个参数。并且我们会尽早生成输出列表的结构,将(:)
称为最外层函数调用。
lazyChunksOf :: [a] -> [b] -> [[b]]
lazyChunksOf as bs = bb : case be of
[] -> []
_ -> lazyChunksOf as be
where ~(bb, be) = lazySplitAt as bs
有了这些内容之后,我们可以使用基本上相同的实现,将我们的惰性变体替换为length
/ (<=)
/ chunksOf
。
zipCycle :: [a] -> [b] -> [[(a,b)]]
zipCycle [] _ = []
zipCycle _ [] = []
zipCycle as bs = zip as bs : case lazyCompare as bs of
LazyLT bt -> lazyChunksOf as (zip (cycle as) bt)
LazyEQ -> []
LazyGT at -> lazyChunksOf bs (zip at (cycle bs))
我们可以在ghci中试用:
> zipCycle "hi" "hello"
[[('h','h'),('i','e')],[('h','l'),('i','l')],[('h','o')]]
无限列表可以很好地用作任一参数:
> take 3 $ zipCycle "hi" [1..]
[[('h',1),('i',2)],[('h',3),('i',4)],[('h',5),('i',6)]]
> take 3 $ zipCycle [1..] "hi"
[[(1,'h'),(2,'i')],[(3,'h'),(4,'i')],[(5,'h'),(6,'i')]]
...或同时作为两个参数:
> take 1 . map (take 3) $ zipCycle [1..] [1..]
[[(1,1),(2,2),(3,3)]]
答案 3 :(得分:0)
您采用了正确的方法,但是只需要使其具有递归性即可,而不是枚举经过的周期数:
splitList :: [a] -> [b] -> [[(a,b)]]
splitList as [] = []
splitList as bs = zip as bs : splitList as (drop (length as) bs)
例如,
splitList [1,2] [1..10]
== zip [1,2] [1..10] : splitList [1,2] [3..10]
== zip [1,2] [1..10] : zip [1,2] [3..10] : splitList [1,2] [5..10]
== ...
== zip [1,2] [1..10] : zip [1,2] [3..10] : ... : zip [1,2] [9,10] : splitList [1,2] []
== zip [1,2] [1..10] : zip [1,2] [3..10] : ... : zip [1,2] [9,10] : []
...
== [[(1,1),(2,2)],[(1,3),(2,4)],...,[(1,9),(2,10)]]