簡體   English   中英

用文件夾在haskell中實現插入

[英]Implement insert in haskell with foldr

如何在Haskell中使用文件夾實現插入。 我試過了:

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]

在最后一個示例中,前2個插入了一個。

編輯:謝謝@李。

我現在有這個:

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> = y更改為x> y。)

(如何將此標記為已回答?)

為此,您需要同

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來模仿同態init . tails init . tails ,如此處所示: 需要根據元素的升序中斷將列表分為多個列表(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

編碼同態的另一種方法是通過函數鏈,如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]

與他的答案中的版本不同,這不會在插入點之后復制列表結構的其余部分(這可能是由於同形的“吃蛋糕也吃蛋糕”)。

這是我的看法:

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

我想折疊在這里不方便。 它總是處理list的所有元素,但是您需要先停止然后再找到第一次出現的元素。 當然可以,但是您可能不想使用:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM