Navigate the list except for the last item in the list

What is the best way to map all items in a list except the last item in a list?

Let's say we have a list let l = [1,2,3,4] and we want to get [2,3,4,4] .

I have a solution, but it doesn't seem like a “functional” way to do this (in ghci):

 let l = [1,2,3,4] let len = toIntegral $ length l -- to avoid a type mismatch Integer <-> Int let l1 = zip l [1..] let l2 = map (\(x,y) -> if y < len then (x + 1,y) else (x,y)) l1 let l3 = map (fst) l2 

Not very nice ... I hope there is a better way! Since I'm new to functional programming, I don't know where to start looking for it.

+7
source share
5 answers

Just rewrite map , but create a special case where there is only one element:

 mapBut1 :: (a -> a) -> [a] -> [a] mapBut1 f [] = [] mapBut1 f [x] = [x] mapBut1 f (x:xs) = fx : mapBut1 f xs 

Now it will work even for infinite lists, it is much faster than calculating the length, and makes it more readable. Note that this restricts your function to a -> a instead of a -> b .

Alternatively you can do

 mapBut1 f (x:y:xs) = fx : mapBut1 f (y:xs) mapBut1 f other = other 

They are equivalent to definitions, but the latter uses 1 lesser pattern match. I would prefer the first, though, especially since it immediately becomes apparent which cases are being processed.

+13
source

This is a quest for a porch-paramorphism, as usual:

 import Data.List (tails) mapButLast :: (a -> a) -> [a] -> [a] mapButLast f = foldr g [] . tails where g (x:_:_) r = fx : r g xs _ = xs 

Or with the correct para we just write

 mapButLast f = para g [] where gx [] r = [x] gx _ r = fx : r 

Where

 para fz (x:xs) = fx xs (para fz xs) para fz [] = z 
+9
source

You can also use init and last from the standard librairies (without special import) if you don't care about appearances .

You can write

 map f (init list) ++ [last list] 

Where

  • f : the function you want to display
  • list : the list you want to display on top
+3
source

What makes this last element so special?

I know that it does not answer your question, but I would think of a type like

 data Foo a = Foo a [a] 

and corresponding Functor.

+1
source

I just want to add an alternative using list comprehension and trying to compare solutions (the first time I try let me know if I don't do it right)

 reverse $ last l : [fx | x <- tail (reverse l)] 

It is slower than most other solutions (see report link below).

Here is an example program ( allbutlast.hs ). It has all the solutions listed above, a simple quickcheck test and a benchmark using criterion .

Prerequisites for launching: QuickCheck and criteria

 cabal update cabal install QuickCheck cabal install -j --disable-tests criterion 

Execution

 ghc -O2 --make allbutlast.hs ./allbutlast --output allbutlast.html 

Report Example: Criteria Report for allbutlast

0
source

Source: https://habr.com/ru/post/975305/


All Articles