如何在haskell中使用foldr实现插入。 我试过了:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = foldr (\x -> \y -> if x<y then x:y else y:x) [e] xs
没有骰子。 我必须在列表中插入元素e,以便它在大于或等于它的第一个元素之前。
示例:
insert'' 2.5 [1,2,3] => [1.0,2.0,2.5,3.0]
insert'' 2.5 [3,2,1] => [2.5,3.0,2.0,1.0]
insert'' 2 [1,2,1] => [1,2,2,1]
在最后一个例子中,第一个插入了一个。
编辑: 谢谢@Lee。
我现在有这个:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = insert2 e (reverse xs)
insert2 e = reverse . snd . foldr (\i (done, l) -> if (done == False) && (vj e i) then (True, e:i:l) else (done, i:l)) (False, [])
where vj e i = e<=i
但是因为这不起作用:
insert'' 2 [1,3,2,3,3] => [1,3,2,2,3,3]
insert'' 2 [1,3,3,4] => [1,3,2,3,4]
insert'' 2 [4,3,2,1] => [4,2,3,2,1]
解决方案:
insert'' :: Ord a => a -> [a] -> [a]
insert'' x xs = foldr pom poc xs False
where
pom y f je
| je || x > y = y : f je
| otherwise = x : y : f True
poc True = []
poc _ = [x]
谢谢@Pedro Rodrigues(它只是将x&gt; = y更改为x&gt; y。)
(如何将其标记为已回答?)
答案 0 :(得分:3)
您需要paramorphism:
para :: (a -> [a] -> r -> r) -> r -> [a] -> r
foldr :: (a -> r -> r) -> r -> [a] -> r
para c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x (foldr c n xs)
para _ n [] = n
foldr _ n [] = n
用它,
insert v xs = para (\x xs r -> if v <= x then (v:x:xs) else (x:r)) [v] xs
我们可以模仿foldr
超过init . tails
的参数,如下所示:Need to partition a list into lists based on breaks in ascending order of elements (Haskell)。
因此解决方案是
import Data.List (tails)
insert v xs = foldr g [v] (init $ tails xs)
where
g xs@(x:_) r | v <= x = v : xs
| otherwise = x : r
对paramorphisms进行编码的另一种方法是通过一系列函数(如answer by Pedro Rodrigues中所示)来安排从左到右的信息流,同时传递第二个副本输入列表本身作为参数(复制tails
的效果):
insert v xs = foldr g (\ _ -> [v]) xs xs
where
g x r xs | v > x = x : r (tail xs) -- xs =@= (x:_)
| otherwise = v : xs
-- visual aid to how this works, for a list [a,b,c,d]:
-- g a (g b (g c (g d (\ _ -> [v])))) [a,b,c,d]
与他的答案中的版本不同,这不会在插入点之后复制列表结构的其余部分(这可能是因为paramorphism的“吃蛋糕而且也吃了”)。
答案 1 :(得分:2)
以下是我的看法:
insert :: Ord a => a -> [a] -> [a]
insert x xs = foldr aux initial xs False
where
aux y f done
| done || x > y = y : f done
| otherwise = x : y : f True
initial True = []
initial _ = [x]
然而,使用foldr
的恕我直言不是最适合这个问题,对我来说,以下解决方案更容易理解:
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x z@(y : ys)
| x <= y = x : z
| otherwise = y : insert x ys
答案 2 :(得分:1)
我认为折叠在这里不方便。它总是处理列表的所有元素,但是你需要先停止然后找到第一个出现的元素。 当然有可能,但你可能不想使用它:
insert' l a = snd $ foldl (\(done, l') b -> if done then (True, l'++[b]) else if a<b then (False, l'++[b]) else (True, l'++[a,b])) (False, []) l