将列表拆分为Haskell中的子列表

时间:2014-02-21 11:38:51

标签: haskell

如何将列表拆分为2个子列表,其中第一个子列表包含从初始列表的开头到等于第一个元素的元素,第二个子列表包含其他元素?我必须在不使用Prelude函数的情况下解决这个问题。

我的基本解决方案是:

partSameElems :: [a] -> ([a],[a])
partSameElems [] = ([],[])
partSameElems (x:xs) = fstList (x:xs) scdList (x:xs)
    where 
        fstList (x:y:xs) = if x == y then x:y:fstList xs {- I need to do Nothing in else section? -} 
        scdList (x:xs) = x:scdList xs

例如: [3,3,3,3,2,1,3,3,6,3] -> ([3,3,3,3], [2,1,3,3,6,3])

现在我可以提供我的解决方案版本:

partSameElems :: Eq a => [a] -> ([a],[a])
partSameElems [] = ([],[])
partSameElems (x:xs) = (fstList (x:xs), scdList (x:xs))
where
    fstList [] _ = []
    fstList (x:xs) el = if x == el then x:fstList xs el else []
    scdList [] _ = []
    scdList (x:xs) el = if x /= el then (x:xs) else  scdList xs el

3 个答案:

答案 0 :(得分:2)

如果你不尝试两次通过,这会更容易。

parSameElems [] = ([], [])
parSameElems lst = (reverse revxs, ys)
  where (revxs, ys) = accum [] lst
        accum xs [y] = ((y:xs), [])
        accum xs (y1:y2:ys) | y1 == y2 = accum (y1:xs) (y2:ys)
                            | otherwise = ((y1:xs), (y2:ys))

不确定您可以在where子句中使用保护语法。你也必须自己实现反向,因为你不能使用Prelude,但这很容易。

注意:我实际上并没有运行它。确保你尝试调试它。

另外,请勿自行编写类型签名。让ghci告诉你。你第一次尝试就弄错了。

答案 1 :(得分:0)

我认为“不使用Prelude功能”意味着它具有教育意义。考虑到它对List数据的操纵,可能旨在处理递归。所以让我们强调这个

当输入和输出类型相同时,递归算法更容易表达。 更确切地说,输入数据由

组成,而不是列表[3,3,3,3,2,1,3,3,6,3]
  • 前面的列表,但在这个阶段它是空的
  • 剩余部分,在此阶段等于输入[3,3,3,2,1,3,3,6,3]
  • 然后
  • 递归输入([],[3,3,3,2,1,3,3,6,3])

中心函数的类型为([a],[a]) -> ([a],[a])

现在,每个递归步骤将采用余数的前面元素,并将if放在前面列表中或停止递归(您到达最终状态并可以返回结果)

module SimpleRecursion where
moveInFront :: (Eq a) => ([a],[a]) -> ([a],[a])
moveInFront (xs    , []   ) =                ( xs    , [])
moveInFront ([]    , y:ys ) =                moveInFront ( y:[]  , ys)
moveInFront (x:xs  , y:ys ) = if x == y then moveInFront ( y:x:xs  , ys) 
                                        else (x:xs, y:ys)

partSameElems :: (Eq a) => [a] -> ([a],[a])
partSameElems a = moveInFront ([],a)

我们这里有一个经典的递归方案,有      - 停止条件(x / = y)      - 递归条款      - 覆盖琐碎的案件

备注:      - 写y:x:xs实际上反转了前面列表,但由于所有值都相等,结果都可以       请不要在实际程序的代码中做那种技巧,它最终会回来咬你      - 该函数仅适用于Equatable数据(Eq a) =>列表,因为递归/停止条件是相等性测试==

答案 2 :(得分:0)

另一种实现可以是

partition [] = ([],[])
partition xa@(x:xs) = (f,s)
              where
                   f = takeWhile (==x) xa
                   s = drop (length f) xa

应该清楚它的作用。

> partition [3,3,3,3,2,1,3,3,6,3]
([3,3,3,3],[2,1,3,3,6,3])