I have this list:
[[0,4,1,4],[1,12,1,4],[2,8,1,4],[3,54,2,4],[4,1,2,2]]
I also have another list: [2,3] -- Represents the indexes i want to get from each sublist
Output should be like:
[[1,4],[1,4],[1,4],[2,4],[2,2]]
Another example:
List :
[[0,4,1,4],[1,12,1,4],[2,8,1,4],[3,54,2,4],[4,1,2,2]]
Indexes : [0,2,3]
Output should be like:
[[0,1,4],[1,1,4],[2,1,4],[3,2,4],[4,2,2]]
You obtain the item in a list with a given index with (!!) :: [a] -> Int -> a, for example:
Prelude> [0,4,1,4] !! 0
0
Prelude> [0,4,1,4] !! 2
1
Prelude> [0,4,1,4] !! 3
4
We thus can perform a mapping to obtain the items for a list of items:
Prelude> map ([0,4,1,4] !!) [0,2,3]
[0,1,4]
we thus can slice a list of lists with:
slices :: [Int] -> [[a]] -> [[a]]
slices is = map ((`map` is) . (!!))
For example:
Prelude> slices [0,2,3] [[0,4,1,4],[1,12,1,4],[2,8,1,4],[3,54,2,4],[4,1,2,2]]
[[0,1,4],[1,1,4],[2,1,4],[3,2,4],[4,2,2]]
Using (!!) is however unsafe: it is not guaranteed that a list has an element with the given index, furthermore, it is not very efficient: it takes O(k) to obtain the k-th element. Therefore it is better to work with Vector or an Array and with lookups that return a Nothing when the index is out of range, for example for a Vector, we can use (!?) :: Vector a -> Int -> Maybe a.
If the elements are always 4-tuples consider using a specialized type for it (Linear.V4)
type V4 :: Type -> Type
data V4 a = V4 a a a a
along with an indexing type that gives total indexing, because we know V4 has a static size (this is because V4 is a Representable functor):
type Fin4 :: Type
data Fin4 = Fin0 | Fin1 | Fin2 | Fin3
infixl 9 !!!
(!!!) :: V4 a -> Fin4 -> a
V4 a _ _ _ !!! Fin0 = a
V4 _ a _ _ !!! Fin1 = a
V4 _ _ a _ !!! Fin2 = a
V4 _ _ _ a !!! Fin3 = a
This is enough to define slices using Willem's definition
slices :: [Fin4] -> [V4 a] -> [[a]]
slices is = map ((`map` is) . (!!!))
>> slices [Fin2, Fin3] example
[[1,4],[1,4],[1,4],[2,4],[2,2]]
>> slices [Fin0, Fin2, Fin3] example
[[0,1,4],[1,1,4],[2,1,4],[3,2,4],[4,2,2]]
This can be generalized for vectors of any length
type N :: Type
data N = O | S N
infixr 5 :>
type Vec :: N -> Type -> Type
data Vec n a where
VNil :: Vec O a
(:>) :: a -> Vec n a -> Vec (S n) a
deriving stock
instance Show a => Show (Vec n a)
deriving stock
instance Functor (Vec n)
type Fin :: N -> Type
data Fin n where
FinO :: Fin (S n)
FinS :: Fin n -> Fin (S n)
infixl 9 !!!
(!!!) :: Vec n a -> Fin n -> a
VNil !!! fin = case fin of
(a:>as) !!! FinO = a
(a:>as) !!! FinS fin = as !!! fin
slices :: [Fin n] -> [Vec n a] -> [[a]]
slices = ..
example :: [Vec (S (S (S (S O)))) Int]
example =
[ 0:>4:>1:>4:>VNil
, 1:>12:>1:>4:>VNil
, 2:>8:>1:>4:>VNil
, 3:>54:>2:>4:>VNil
, 4:>1:>2:>2:>VNil
]
Indices and lists of tuples can be generalized to work for any functor
slices :: Functor f => Functor g => f (Fin n) -> g (Vec n b) -> g (f b)
slices is = fmap ((`fmap` is) . (!!!))
If we treat the list of examples as an 5-ary vector
example :: Vec (S (S (S (S (S O))))) (Vec (S (S (S (S O)))) Int)
example
= (0:>4:>1:>4:>VNil)
:> (1:>12:>1:>4:>VNil)
:> (2:>8:>1:>4:>VNil)
:> (3:>54:>2:>4:>VNil)
:> (4:>1:>2:>2:>VNil)
:> VNil
>> slices (FinS (FinS FinO) :> FinS (FinS (FinS FinO)) :> VNil) example
(1 :> 4 :> VNil)
:> (1 :> 4 :> VNil)
:> (1 :> 4 :> VNil)
:> (2 :> 4 :> VNil)
:> (2 :> 2 :> VNil)
:> VNil
Related
I want to rewrite (or upgrade! :) ) my two functions, hist and sort, using fold-functions. But since I am only in the beginning of my Haskell-way, I can't figure out how to do it.
First of all, I have defined Insertion, Table and imported Data.Char:
type Insertion = (Char, Int)
type Table = [Insertion]
import Data.Char
Then I have implemented the following code for hist:
hist :: String -> Table
hist[] = []
hist(x:xs) = sortBy x (hist xs) where
sortBy x [] = [(x,1)]
sortBy x ((y,z):yzs)
| x == y = (y,z+1) : yzs
| otherwise = (y,z) : sortBy x yzs
And this one for sort:
sort :: Ord a => [a] -> [a]
sort [] = []
sort (x:xs) = paste x (sort xs)
paste :: Ord a => a -> [a] -> [a]
paste y [] = [y]
paste y (x:xs)
| x < y = x : paste y xs
| otherwise = y : x : xs
What can I do next? How can I use the fold-functions to implement them?
foldr f z on a list replaces the "cons" of the list (:) with f and the empty list [] with z.
This thus means that for a list like [1,4,2,5], we thus obtain f 1 (f 4 (f 2 (f 5 z))), since [1,4,2,5] is short for 1 : 4 : 2 : 5 : [] or more canonical (:) 1 ((:) 4 ((:) 2 ((:) 5 []))).
The sort function for example can be replaced with a fold function:
sort :: Ord a => [a] -> [a]
sort = foldr paste []
since sort [1,4,2,5] is equivalent to paste 1 (paste 4 (paste 2 (paste 5 []))). Here f thus takes as first parameter an element, and as second parameter the result of calling foldr f z on the rest of the list,
I leave hist as an exercise.
I have list of lists of Int and I need to add an Int value to the last list from the list of lists. How can I do this? My attempt is below
f :: [[Int]] -> [Int] -> Int -> Int -> Int -> [[Int]]
f xs [] cur done total = [[]]
f xs xs2 cur done total = do
if total >= length xs2 then
xs
else
if done == fib cur then
f (xs ++ [[]]) xs2 (cur + 1) 0 total
else
f ((last xs) ++ [[xs2!!total]]) xs2 cur (done + 1) (total + 1)
The problem is:
We have a list A of Int
And we need to slpit it on N lists B_1 ,..., B_n , length of B_i is i-th Fibonacci number.
If we have list [1 , 2 , 3 , 4 , 5 , 6 , 7] (xs2 in my code)
The result should be [[1] , [2] , [3 , 4] , [5 , 6 , 7]]
The easy way to deal with problems like this is to separate the problem into sub-problems. In this case, you want to change the last item in a list. The way you want to change it is by adding an item to it.
First let's tackle changing the last item of a list. We'll do this by applying a function to the last item, but not to any other items.
onLast :: [a] -> (a -> a) -> [a]
onLast xs f = go xs
where
go [] = []
go [x] = [f x]
go (x:xs) = x:go xs
You want to change the last item in the list by adding an additional value, which you can do with (++ [value]).
Combining the two with the value you want to add (xs2!!total) we get
(onLast xs (++ [xs2!!total]))
f :: [[Int]] -> Int -> [[Int]]
f [] _ = []
f xs i = (take n xs) ++ [[x + i | x <- last xs]]
where n = (length xs) - 1
last = head . (drop n)
For example,
*Main> f [[1, 2, 3], [], [4, 5, 6]] 5
[[1,2,3],[],[9,10,11]]
*Main> f [[1, 2, 3]] 5
[[6,7,8]]
*Main> f [] 3
You approach uses a do block, this is kind of weird since do blocks are usually used for monads. Furthermore it is rather unclear what cur, done and total are doing. Furthermore you use (!!) :: [a] -> Int -> a and length :: [a] -> Int. The problem with these functions is that these run in O(n), so it makes the code inefficient as well.
Based on changed specifications, you want to split the list in buckets with length the Fibonacci numbers. In that case the signature should be:
f :: [a] -> [[a]]
because as input you give a list of numbers, and as output, you return a list of numbers. We can then implement that as:
f :: [a] -> [[a]]
f = g 0 1
where g _ _ [] = []
g a b xs = xa : g b (a+b) xb
where (xa,xb) = splitAt b xs
This generates:
*Main> f [1,2,3,4,5,6]
[[1],[2],[3,4],[5,6]]
*Main> f [1,2,3,4,5,6,7]
[[1],[2],[3,4],[5,6,7]]
*Main> f [1,2,3,4,5,6,7,8]
[[1],[2],[3,4],[5,6,7],[8]]
*Main> f [1,2,3,4,5,6,7,8,9]
[[1],[2],[3,4],[5,6,7],[8,9]]
The code works as follows: we state that f = g 0 1 so we pass the arguments of f to g, but g also gets an 0 and a 1 (the first Fibonacci numbers).
Each iteration g checks whether we reached the end of the list. If so, we return an empty list as well. Otherwise we determine the last Fibonacci number that far (b), and use a splitAt to obtain the first b elements of the list we process, as well as the remainder. We then emit the first part as head of the list, and for the tail we calculate the next Fibonacci number and pass that to g with the tail of splitAt.
How should one convert a list with a known length into nested pairs? In other words, what is the most convenient way to fill the type holes below?
_ [1,2] :: (Int,Int)
_ [1,2,3] :: ((Int,Int),Int)
_ [1,2,3,4] :: (((Int,Int),Int),Int)
_ [1,2,3,4,5] :: ((((Int,Int),Int),Int),Int)
EDIT: note that the type holes need not be the same function, I'm looking for a convenient pattern (if a convenient pattern exists) to fill the holes.
Perhaps like this:
step f xs = (f (init xs), last xs)
len1 = head
len2 = step len1
len3 = step len2
len4 = step len3
In ghci:
*Main> len4 [1..4]
(((1,2),3),4)
One may of course also directly implement one of these functions with pattern matching:
len4' [a,b,c,d] = (((a,b),c),d)
This will also not traverse the list as many times as there are elements, which is nice.
Chiming in with a dependently typed version. First, let's get done with the boilerplate:
{-# LANGUAGE
TemplateHaskell, DataKinds, ScopedTypeVariables,
FlexibleInstances, PolyKinds, TypeOperators,
TypeFamilies, GADTs, UndecidableInstances #-}
import Data.Singletons.TH
import qualified GHC.TypeLits as Lit
$(singletons [d| data Nat = Z | S Nat deriving (Eq, Show) |])
The use of TH here is purely for boilerplate reduction and we won't use TH in our actual code. In fact, the above could be (and should be) factored out in a package somewhere (at the time of writing this answer there isn't such a package with up-to-date singletons dependency).
tuplify becomes a function whose return type depends on a Nat parameter.
type family NTup n a where
NTup (S (S Z)) a = (a, a)
NTup (S (S (S n))) a = (NTup (S (S n)) a, a)
tuplify :: Sing n -> [a] -> NTup n a
tuplify n as = go n (reverse as) where
go :: Sing n -> [a] -> NTup n a
go (SS (SS SZ)) [a, b] = (b, a)
go (SS (SS (SS n))) (a:as) = (go (SS (SS n)) as, a)
go _ _ = error "tuplify: length mismatch"
Trying it out:
tuplify (SS (SS (SS SZ))) [1, 2, 3] -- ((1, 2), 3)
Writing out the naturals is quite arduous now, so let's introduce some syntactic sugar:
type family N n where
N 0 = Z
N n = S (N (n Lit.- 1))
type SN n = Sing (N n)
Now:
tuplify (sing:: SN 10) [1..10] -- (((((((((1,2),3),4),5),6),7),8),9),10)
As a side note, if we convert the empty list to () (and thereby also allow one-element nested tuples) our definitions become much more natural:
type family NTup n a where
NTup Z a = ()
NTup (S n) a = (NTup n a, a)
tuplify :: Sing n -> [a] -> NTup n a
tuplify n = go n . reverse where
go :: Sing n -> [a] -> NTup n a
go SZ [] = ()
go (SS n) (a:as) = (go n as, a)
go _ _ = error "tuplify: length mismatch"
tuplify (sing:: SN 5) [1..5] -- ((((((),1),2),3),4),5)
This would be a nice exercise in Agda with dependent types. In Haskell you can achieve something close with (also inspired from Daniel Wagner's solution)
class C a b where
listToTuple :: [a] -> b
instance C a a where
listToTuple [x] = x
instance C a b => C a (b,a) where
listToTuple xs = (listToTuple (init xs), last xs)
Some tests:
> listToTuple [1..3::Int] :: ((Int,Int),Int)
((1,2),3)
> listToTuple [0..3::Int] :: (((Int,Int),Int),Int)
(((0,1),2),3)
Note that the return type annotation is mandatory, otherwise Haskell can not deduce how many elements the return tuple must have. If there is a mismatch between the tuple and list length, a run-time error occurs. This is pretty much unavoidable since lists do not carry their length in their type, so the compiler can not check this earlier (unlike using a vector GADT).
In order to have such a generic and type-safe function, you'd need dependent types so that the number of nested tuples in the result could depend on the length of the input list.
However it's possible to get close to that with polymorphic recursion.
Let's define a data type as follows:
data TupleList' r a = Value r | Tuple (TupleList' (r, a) a)
deriving (Show, Read, Eq, Ord)
type TupleList = TupleList' ()
So a value of type TupleList a is isomorphic to (), ((), a), (((), a), a) etc, depending on how many Tuple constructors wrap the final Value.
Now we can convert a list into such a tuple as follows:
fromList :: [a] -> TupleList a
fromList = loop ()
where
loop :: r -> [a] -> TupleList' r a
loop r [] = Value r
loop r (x:xs) = Tuple (loop (r, x) xs)
Notice that loop uses polymorphic recursion (as any function that operates on TupleList' - its recursive call has signature (r, a) -> [a] -> TupleList' (r, a) a.
Example: mapM_ (print . fromList) (inits [1..4]) yields
Value ()
Tuple (Value ((),1))
Tuple (Tuple (Value (((),1),2)))
Tuple (Tuple (Tuple (Value ((((),1),2),3))))
Tuple (Tuple (Tuple (Tuple (Value (((((),1),2),3),4)))))
The simplest way is
z (x:xs) = x
s r (x:xs) = (x, r xs)
toTuples n xs = n xs
But toTuples returns pairs in the reverse order:
toTuples (s (s (s z))) [1..] == (1,(2,(3,4)))
We can use CPS to fix this:
z f xs = f ()
s r f (x:xs) = r (\p -> (f p, x)) xs
toTuples n (x:xs) = n (const x) xs
Then
toTuples (s (s (s z))) [1..] == (((1,2),3),4)
And we can define some syntactic sugar (I'm mostly stealing from András Kovács' answer):
{-# LANGUAGE TemplateHaskell, UndecidableInstances, DataKinds, GADTs, TypeFamilies, TypeOperators #-}
import Data.Singletons.TH
import GHC.TypeLits
$(singletons [d| data Nat = Z | S Nat deriving (Eq, Show) |])
z f xs = f ()
s r f (x:xs) = r (\p -> (f p, x)) xs
toTuples n (x:xs) = n (const x) xs
type family Result n r a where
Result Z r a = r
Result (S n) r a = Result n (r, a) a
run :: Sing n -> (() -> r) -> [a] -> Result n r a
run SZ = z
run (SS sn) = s (run sn)
toTuplesN :: Sing n -> [a] -> Result n a a
toTuplesN sn (x:xs) = run sn (const x) xs
type family N n where
N 0 = Z
N n = S (N (n - 1))
type SN n = Sing (N (n - 1))
main = print $ toTuplesN (sing :: SN 6) [1..] -- (((((1,2),3),4),5),6)
Note that the code works for infinite lists too, since there is no reversing.
I'm looking for a function in haskell to zip two lists that may vary in length.
All zip functions I could find just drop all values of a lists that is longer than the other.
For example:
In my exercise I have two example lists.
If the first one is shorter than the second one I have to fill up using 0's. Otherwise I have to use 1's.
I'm not allowed to use any recursion. I just have to use higher order functions.
Is there any function I can use?
I really could not find any solution so far.
There is some structure to this problem, and here it comes. I'll be using this stuff:
import Control.Applicative
import Data.Traversable
import Data.List
First up, lists-with-padding are a useful concept, so let's have a type for them.
data Padme m = (:-) {padded :: [m], padder :: m} deriving (Show, Eq)
Next, I remember that the truncating-zip operation gives rise to an Applicative instance, in the library as newtype ZipList (a popular example of a non-Monad). The Applicative ZipList amounts to a decoration of the monoid given by infinity and minimum. Padme has a similar structure, except that its underlying monoid is positive numbers (with infinity), using one and maximum.
instance Applicative Padme where
pure = ([] :-)
(fs :- f) <*> (ss :- s) = zapp fs ss :- f s where
zapp [] ss = map f ss
zapp fs [] = map ($ s) fs
zapp (f : fs) (s : ss) = f s : zapp fs ss
I am obliged to utter the usual incantation to generate a default Functor instance.
instance Functor Padme where fmap = (<*>) . pure
Thus equipped, we can pad away! For example, the function which takes a ragged list of strings and pads them with spaces becomes a one liner.
deggar :: [String] -> [String]
deggar = transpose . padded . traverse (:- ' ')
See?
*Padme> deggar ["om", "mane", "padme", "hum"]
["om ","mane ","padme","hum "]
This can be expressed using These ("represents values with two non-exclusive possibilities") and Align ("functors supporting a zip operation that takes the union of non-uniform shapes") from the these library:
import Data.Align
import Data.These
zipWithDefault :: Align f => a -> b -> f a -> f b -> f (a, b)
zipWithDefault da db = alignWith (fromThese da db)
salign and the other specialised aligns in Data.Align are also worth having a look at.
Thanks to u/WarDaft, u/gallais and u/sjakobi over at r/haskell for pointing out this answer should exist here.
You can append an inifinte list of 0 or 1 to each list and then take the number you need from the result zipped list:
zipWithDefault :: a -> b -> [a] -> [b] -> [(a,b)]
zipWithDefault da db la lb = let len = max (length la) (length lb)
la' = la ++ (repeat da)
lb' = lb ++ (repeat db)
in take len $ zip la' lb'
This should do the trick:
import Data.Maybe (fromMaybe)
myZip dx dy xl yl =
map (\(x,y) -> (fromMaybe dx x, fromMaybe dy y)) $
takeWhile (/= (Nothing, Nothing)) $
zip ((map Just xl) ++ (repeat Nothing)) ((map Just yl) ++ (repeat Nothing))
main = print $ myZip 0 1 [1..10] [42,43,44]
Basically, append an infinite list of Nothing to the end of both lists, then zip them, and drop the results when both are Nothing. Then replace the Nothings with the appropriate default value, dropping the no longer needed Justs while you're at it.
No length, no counting, no hand-crafted recursions, no cooperating folds. transpose does the trick:
zipLongest :: a -> b -> [a] -> [b] -> [(a,b)]
zipLongest x y xs ys = map head . transpose $ -- longest length;
[ -- view from above:
zip xs
(ys ++ repeat y) -- with length of xs
, zip (xs ++ repeat x)
ys -- with length of ys
]
The result of transpose is as long a list as the longest one in its input list of lists. map head takes the first element in each "column", which is the pair we need, whichever the longest list was.
(update:) For an arbitrary number of lists, efficient padding to the maximal length -- aiming to avoid the potentially quadratic behaviour of other sequentially-combining approaches -- can follow the same idea:
padAll :: a -> [[a]] -> [[a]]
padAll x xss = transpose $
zipWith const
(transpose [xs ++ repeat x | xs <- xss]) -- pad all, and cut
(takeWhile id . map or . transpose $ -- to the longest list
[ (True <$ xs) ++ repeat False | xs <- xss])
> mapM_ print $ padAll '-' ["ommmmmmm", "ommmmmm", "ommmmm", "ommmm", "ommm",
"omm", "om", "o"]
"ommmmmmm"
"ommmmmm-"
"ommmmm--"
"ommmm---"
"ommm----"
"omm-----"
"om------"
"o-------"
You don't have to compare list lengths. Try to think about your zip function as a function taking only one argument xs and returning a function which will take ys and perform the required zip. Then, try to write a recursive function which recurses on xs only, as follows.
type Result = [Int] -> [(Int,Int)]
myZip :: [Int] -> Result
myZip [] = map (\y -> (0,y)) -- :: Result
myZip (x:xs) = f x (myZip xs) -- :: Result
where f x k = ??? -- :: Result
Once you have found f, notice that you can turn the recursion above into a fold!
As you said yourself, the standard zip :: [a] -> [b] -> [(a, b)] drops elements from the longer list. To amend for this fact you can modify your input before giving it to zip. First you will have to find out which list is the shorter one (most likely, using length). E.g.,
zip' x xs y ys | length xs <= length ys = ...
| otherwise = ...
where x is the default value for shorter xs and y the default value for shorter ys.
Then you extend the shorter list with the desired default elements (enough to account for the additional elements of the other list). A neat trick for doing so without having to know the length of the longer list is to use the function repeat :: a -> [a] that repeats its argument infinitely often.
zip' x xs y ys | length xs <= length ys = zip {-do something with xs-} ys
| otherwise = zip xs {-do something with ys-}
Here is another solution, that does work on infinite lists and is a straightforward upgrade of Prelude's zip functions:
zipDefault :: a -> b -> [a] -> [b] -> [(a,b)]
zipDefault _da _db [] [] = []
zipDefault da db (a:as) [] = (a,db) : zipDefault da db as []
zipDefault da db [] (b:bs) = (da,b) : zipDefault da db [] bs
zipDefault da db (a:as) (b:bs) = (a,b) : zipDefault da db as bs
and
zipDefaultWith :: a -> b -> (a->b->c) -> [a] -> [b] -> [c]
zipDefaultWith _da _db _f [] [] = []
zipDefaultWith da db f (a:as) [] = f a db : zipDefaultWith da db f as []
zipDefaultWith da db f [] (b:bs) = f da b : zipDefaultWith da db f [] bs
zipDefaultWith da db f (a:as) (b:bs) = f a b : zipDefaultWith da db f as bs
#pigworker, thank you for your enlightening solution!
Yet another implementation:
zipWithDefault :: a -> b -> (a -> b -> c) -> [a] -> [b] -> [c]
zipWithDefault dx _ f [] ys = zipWith f (repeat dx) ys
zipWithDefault _ dy f xs [] = zipWith f xs (repeat dy)
zipWithDefault dx dy f (x:xs) (y:ys) = f x y : zipWithDefault dx dy f xs ys
And also:
zipDefault :: a -> b -> [a] -> [b] -> [c]
zipDefault dx dy = zipWithDefault dx dy (,)
I would like to address the second part of Will Ness's solution, with its excellent use of known functions, by providing another to the original question.
zipPadWith :: a -> b -> (a -> b -> c) -> [a] -> [b] -> [c]
zipPadWith n _ f [] l = [f n x | x <- l]
zipPadWith _ m f l [] = [f x m | x <- l]
zipPadWith n m f (x:xs) (y:ys) = f x y : zipPadWith n m f xs ys
This function will pad a list with an element of choice. You can use a list of the same element repeated as many times as the number of lists in another like this:
rectangularWith :: a -> [[a]] -> [[a]]
rectangularWith _ [] = []
rectangularWith _ [ms] = [[m] | m <- ms]
rectangularWith n (ms:mss) = zipPadWith n [n | _ <- mss] (:) ms (rectangularWith n mss)
The end result will have been a transposed rectangular list of lists padded by the element that we provided so we only need to import transpose from Data.List and recover the order of the elements.
mapM_ print $ transpose $ rectangularWith 0 [[1,2,3,4],[5,6],[7,8],[9]]
[1,2,3,4]
[5,6,0,0]
[7,8,0,0]
[9,0,0,0]
I'm new in haskell and I'm looking for some standard functions to work with lists by indexes.
My exact problem is that i want to remove 3 elements after every 5. If its not clear enough here is illustration:
OOOOOXXXOOOOOXXX...
I know how to write huge function with many parameters, but is there any clever way to do this?
Two completely different approaches
You can use List.splitAt together with drop:
import Data.List (splitAt)
f :: [a] -> [a]
f [] = []
f xs = let (h, t) = splitAt 5 xs in h ++ f (drop 3 t)
Now f [1..12] yields [1,2,3,4,5,9,10,11,12]. Note that this function can be expressed more elegantly using uncurry and Control.Arrow.second:
import Data.List (splitAt)
import Control.Arrow (second)
f :: [a] -> [a]
f [] = []
f xs = uncurry (++) $ second (f . drop 3) $ splitAt 5 xs
Since we're using Control.Arrow anyway, we can opt to drop splitAt and instead call in the help of Control.Arrow.(&&&), combined with take:
import Control.Arrow ((&&&))
f :: [a] -> [a]
f [] = []
f xs = uncurry (++) $ (take 5 &&& (f . drop 8)) xs
But now it's clear that an even shorter solution is the following:
f :: [a] -> [a]
f [] = []
f xs = take 5 xs ++ (f . drop 8) xs
As Chris Lutz notes, this solution can then be generalized as follows:
nofm :: Int -> Int -> [a] -> [a]
nofm _ _ [] = []
nofm n m xs = take n xs ++ (nofm n m . drop m) xs
Now nofm 5 8 yields the required function. Note that a solution with splitAt may still be more efficient!
Apply some mathematics using map, snd, filter, mod and zip:
f :: [a] -> [a]
f = map snd . filter (\(i, _) -> i `mod` 8 < (5 :: Int)) . zip [0..]
The idea here is that we pair each element in the list with its index, a natural number i. We then remove those elements for which i % 8 > 4. The general version of this solution is:
nofm :: Int -> Int -> [a] -> [a]
nofm n m = map snd . filter (\(i, _) -> i `mod` m < n) . zip [0..]
Here is my take:
deleteAt idx xs = lft ++ rgt
where (lft, (_:rgt)) = splitAt idx xs
You can count your elements easily:
strip' (x:xs) n | n == 7 = strip' xs 0
| n >= 5 = strip' xs (n+1)
| n < 5 = x : strip' xs (n+1)
strip l = strip' l 0
Though open-coding looks shorter:
strip (a:b:c:d:e:_:_:_:xs) = a:b:c:d:e:strip xs
strip (a:b:c:d:e:xs) = a:b:c:d:e:[]
strip xs = xs
Since nobody did a version with "unfoldr", here is my take:
drop3after5 lst = concat $ unfoldr chunk lst
where
chunk [] = Nothing
chunk lst = Just (take 5 lst, drop (5+3) lst)
Seems to be the shortest thus far
the take and drop functions may be able to help you here.
drop, take :: Int -> [a] -> [a]
from these we could construct a function to do one step.
takeNdropM :: Int -> Int -> [a] -> ([a], [a])
takeNdropM n m list = (take n list, drop (n+m) list)
and then we can use this to reduce our problem
takeEveryNafterEveryM :: Int -> Int -> [a] -> [a]
takeEveryNafterEveryM n m [] = []
takeEveryNafterEveryM n m list = taken ++ takeEveryNafterEveryM n m rest
where
(taken, rest) = takeNdropM n m list
*Main> takeEveryNafterEveryM 5 3 [1..20]
[1,2,3,4,5,9,10,11,12,13,17,18,19,20]
since this is not a primitive form of recursion, it is harder to express this as a simple fold.
so a new folding function could be defined to fit your needs
splitReduce :: ([a] -> ([a], [a])) -> [a] -> [a]
splitReduce f [] = []
splitReduce f list = left ++ splitReduce f right
where
(left, right) = f list
then the definition of takeEveryNafterEveryM is simply
takeEveryNafterEveryM2 n m = splitReduce (takeNdropM 5 3)
This is my solution. It's a lot like #barkmadley's answer, using only take and drop, but with less clutter in my opinion:
takedrop :: Int -> Int -> [a] -> [a]
takedrop _ _ [] = []
takedrop n m l = take n l ++ takedrop n m (drop (n + m) l)
Not sure if it'll win any awards for speed or cleverness, but I think it's pretty clear and concise, and it certainly works:
*Main> takedrop 5 3 [1..20]
[1,2,3,4,5,9,10,11,12,13,17,18,19,20]
*Main>
Here is my solution:
remElements step num=rem' step num
where rem' _ _ []=[]
rem' s n (x:xs)
|s>0 = x:rem' (s-1) num xs
|n==0 = x:rem' (step-1) num xs
|otherwise= rem' 0 (n-1) xs
example:
*Main> remElements 5 3 [1..20]
[1,2,3,4,5,9,10,11,12,13,17,18,19,20]
myRemove = map snd . filter fst . zip (cycle $ (replicate 5 True) ++ (replicate 3 False))