haskell 如何使用偶数和奇数位置将列表拆分为两个?

kcrjzv8t  于 2022-12-13  发布在  其他
关注(0)|答案(2)|浏览(155)

我尝试根据列表中的索引/位置将列表分为偶数和奇数。例如,对于列表[2,3,6],结果应该是even = [2,6]odd = [3]
我想使用不使用列表解析的方法--一次匹配两个元素,并将一个放在evens列表中,一个放在odds列表中。
但我不确定如何使用语法。我知道如何在逻辑上使用,但我在语法上很挣扎。以下是我目前所掌握的:

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
dtcbnfnu

dtcbnfnu1#

你就快到了。应该是

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

正如错误消息所提醒的,该函数返回一个 tuple(一对)列表,而不是一个列表,可以将任何内容与之组合(:)。
因此,我们将tuple取入,并将两个head元素中的每一个前置到相应的列表中,将结果重新打包为一对,这样类型就适合了:

( 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
nwlqm0z1

nwlqm0z12#

我修改了代码,添加了一个列表只包含一个元素的情况。这不应该给予任何例外。基本上它会将xy发送到不同的列表。作为第一个元素的x总是奇数,而作为第二个元素的y总是偶数。

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

相关问题