如何将列表拆分为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
答案 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])