如何使用偶数和奇数位置将一个列表分成两个?



我试图根据列表中的索引/位置将列表拆分为偶数和奇数。例如,对于列表[2,3,6],结果应该是even = [2,6]odd = [3]

我想使用不使用列表推导式的方法——一次匹配两个元素,并将一个放在偶数列表中,另一个放在奇数列表中。

但我不确定的语法得到它的工作。我知道如何在逻辑上,但我在努力与语法。以下是目前为止的内容:

splitOnPos :: [a] -> ([a], [a])
splitOnPos [] = ([], [])
splitOnPos (x1:x2:xs) = (odds, evens)   
where 
odds  = x1 : splitOnPos xs
evens = x2 : splitOnPos xs

我得到以下关于类型的错误:

* Couldn't match expected type `[a]' with actual type `([a], [a])'
* In the second argument of `(:)', namely `splitOnPos xs'
In the expression: x2 : splitOnPos xs
In an equation for `evens': evens = x2 : splitOnPos xs

你差一点就成功了。应该是

splitOnPos :: [a] -> ([a], [a])
splitOnPos [] = ([], [])
splitOnPos (x1:x2:xs) = (x1:odds, x2:evens)   
where 
(odds, evens) = splitOnPos xs

正如错误消息提醒您的那样,该函数返回元组(一对)列表,而不仅仅是一个列表,您可以(:)访问任何内容。

因此,我们接受元组,并将两个头元素分别添加到相应的列表中,再次将结果重新打包为一对,因此类型适合:

( x1:odds        <--       ( odds
,                          ,           <---- recursive call
x2:evens )     <--         evens )

你还要在这里写一个方程,这样就涵盖了所有的情况。现在您只处理空列表的情况,以及包含两个或两个以上元素的列表。

不处理单例列表的情况。因此,它只适用于偶数长度的列表:

> splitOnPos [0..9]
([0,2,4,6,8],[1,3,5,7,9])
> splitOnPos [0..10]
([0,2,4,6,8*** Exception: <interactive>:(574,1)-(577,37):
Non-exhaustive patterns in function splitOnPos

我通过添加一个列表只包含一个元素的大小写来修复代码。这不应该有任何例外。基本上它会把x和y发送到不同的列表。X作为第一个元素总是奇数,而y作为第二个元素总是偶数。

splitOE :: [Int] -> ([Int],[Int])
splitOE []       = ([],[])
splitOE [x]      = ([x],[])
splitOE (x:y:xs) = (x:odds, y:evens)   
where 
(odds, evens) = splitOE xs

最新更新