getting every 3rd element & looping back (Haskell) - haskell

I want to write a function that returns every nth element of a given list but then updates the head to the second element and does this again until it has gone through all elements in the list.
I know the code for going through every nth element in a list is:
everyf n [] = []
everyf n as = head as : everyf n (drop n as)
but this does not loop back. How can I get this to update head so that i get the following result:
everyf 3 [1,2,3,4,5,6,7]
returns [[1,4,7],[2,5],[3,6]]

Disclaimer: I don't know haskell (at all) :-)
listOfNths :: Int -> [a] -> [[a]]
listOfNths n xs = map (\x -> everyf n (drop x xs)) [0..n-1]
and a slightly "improved" version:
listOfNths :: Int -> [a] -> [[a]]
listOfNths n xs = map pickEveryf [0..n-1]
where pickEveryf = (everyf n) . (`drop` xs)

Related

What's the most efficient way to take up to the last n elements of a list

To clarify : I want all the elements but the last n
Reading some answers on stackoverflow I get the impression that using length on lists is inadvisable. So is there better way to do this than take (length xs - n) xs?
Yes. You first drop n elements from the list, then walk over the two lists concurrently and when the you hit the end of the list with the dropped version of the list, then you return the list of the "iterator" over the entire list:
takeLast :: Int -> [a] -> [a]
takeLast n ls = go (drop n ls) ls
where go [] ls = ls
go (_:xs) ~(_:ys) = go xs ys
This thus works because the first "iterator" is n steps ahead. So if it hits the end of the list, the second iterator is n steps behind the end of the list.
For example:
Prelude> takeLast 2 [1,4,2,5,1,3,0,2]
[0,2]
Prelude> takeLast 3 [1,4,2,5,1,3,0,2]
[3,0,2]
Prelude> takeLast 4 [1,4,2,5,1,3,0,2]
[1,3,0,2]
Prelude> takeLast 5 [1,4,2,5,1,3,0,2]
[5,1,3,0,2]
We can also drop the last n elements in a similar way:
dropLast :: Int -> [a] -> [a]
dropLast n ls = go (drop n ls) ls
where go [] _ = []
go (_:xs) ~(y:ys) = y : go xs ys
For example:
Prelude> dropLast 2 [1,4,2,5,1,3,0,2]
[1,4,2,5,1,3]
Prelude> dropLast 3 [1,4,2,5,1,3,0,2]
[1,4,2,5,1]
Prelude> dropLast 4 [1,4,2,5,1,3,0,2]
[1,4,2,5]
Prelude> dropLast 5 [1,4,2,5,1,3,0,2]
[1,4,2]
If we operate on an infinite list, then dropLast will still yield elements, whereas if we would use take (length ls - n) ls, it would get stuck in an infinite loop.
We can, as #DanielWagner says use zipWith for this:
dropLast :: Int -> [a] -> [a]
dropLast n xs = zipWith const xs (drop n xs)
Here we let zipWith iterate over both lists, and we use const to each time return the element of the first list.

zip two lists produced by two functions (Haskell)

I have two functions (count and listOfNths) that both take parameters and produce a list. I would like to zip the the lists produced by these two functions. How would I go about doing that?
I tried writing zip listOfNths count but that didn't work.
count n = [ x | x <- [0..n-1]]
everyf n [] = []
everyf n as = head as : everyf n (drop n as)
listOfNths :: Int -> [a] -> [[a]]
listOfNths n xs = map (\x -> everyf n (drop x xs)) [0..n-1]
just a sidenote: the function listOfNths makes use of another function (everyf) but that's not important.
If I understand you correctly, you can do this using a simple map:
fn n xs = map (\x -> (everyf n $ drop x xs, x)) [0..n-1]
If you insist on using a zip, then you have to evaluate the functions prior to zipping:
fn n xs = zip (listOfNths n xs) (count n)

How do I make a list of substrings?

I am trying to make a list of all substrings where each substring has one less element of the originial string.
e.g "1234" would result in ["1234","123","12","1"]
I would like to achieve this only using prelude (no import) so cant use subsequences.
I am new to Haskell, and I know some of the problems with my code but don't currently know how to fix them.
slist :: String -> [String]
slist (x:xs) = (take (length (x:xs)) (x:xs)) ++ slist xs
How can I do this recursively using
Edit: would like to this by using init recursively
slist :: String -> [String]
slist [] = []
-- slist xs = [xs] ++ (slist $ init xs)
slist xs = xs : (slist $ init xs)
main = do
print $ slist "1234"
Here's a very lazy version suitable for working on infinite lists. Each element of each resulting list after the first only requires O(1) amortized time to compute it no matter how far into the list we look.
The general idea is: for each length n we intend to drop off the end we split the list into a queue of items of length n and the remainder of the list. To yield results, we first check there's another item in the list that can take a place in the queue, then yield the first item in the queue. When we reach the end of the list we discard the remaining items from the queue.
import Data.Sequence (Seq, empty, fromList, ViewL (..), viewl, (|>))
starts :: [a] -> [[a]]
starts = map (uncurry shiftThrough) . splits
shiftThrough :: Seq a -> [a] -> [a]
shiftThrough queue [] = []
shiftThrough queue (x:xs) = q1:shiftThrough qs xs
where
(q1 :< qs) = viewl (queue |> x)
splits finds all the initial sequences of a list together with the tailing list.
splits :: [a] -> [(Seq a, [a])]
splits = go empty
where
go s [] = []
go s (x:xs) = (s,x:xs):go (s |> x) xs
We can write dropping from the end of a list in terms of the same strategy.
dropEnd :: Int -> [a] -> [a]
dropEnd n = uncurry (shiftThrough . fromList) . splitAt n
These use Data.Sequence's amortized O(n) construction of a sequence fromList, O(1) appending to the end of sequence with |> and O(1) examining the start of a sequence with viewl.
This is fast enough to query things like (starts [1..]) !! 80000 very quickly and (starts [1..]) !! 8000000 in a few seconds.
Look ma, no imports
A simple purely functional implementation of a queue is a pair of lists, one containing the things to output next in order and one containing the most recent things added. Whenever something is added it's added to the beginning of the added list. When something is needed the item is removed from the beginning of the next list. When there are no more items left to remove from the next list it is replaced by the added list in reverse order, and the added list is set to []. This has amortized O(1) running time since each item will be added once, removed once, and reversed once, however many of the reversals will happen all at once.
delay uses the queue logic described above to implement the same thing as shiftThrough from the previous section. xs is the list of things that were recently added and ys is the list of things to use next.
delay :: [a] -> [a] -> [a]
delay ys = traverse step ([],ys)
where
step (xs, ys) x = step' (x:xs) ys
step' xs [] = step' [] (reverse xs)
step' xs (y:ys) = (y, (xs, ys))
traverse is almost a scan
traverse :: (s -> a -> (b, s)) -> s -> [a] -> [b]
traverse f = go
where
go _ [] = []
go s (x:xs) = y : go s' xs
where (y, s') = f s x
We can define starts in terms of delay and another version of splits that returns lists.
starts :: [a] -> [[a]]
starts = map (uncurry delay) . splits
splits :: [a] -> [([a], [a])]
splits = go []
where
go s [] = []
go s (x:xs) = (reverse s, x:xs):go (x:s) xs
This has very similar performance to the implementation using Seq.
Here's a somewhat convoluted version:
slist xs = go (zip (repeat xs) [lenxs, lenxs - 1..1])
where lenxs = length xs
go [] = []
go (x:xs) = (take (snd x) (fst x)) : go xs
main = do
print $ slist "1234"
Updated answer to list all possible substrings (not just starting from the root).
slist :: [t] -> [[t]]
slist [] = []
slist xs = xs : (slist $ init xs ) # Taken from Pratik Deoghare's post
all_substrings:: [t] -> [[t]]
all_substrings (x:[]) = [[x]]
all_substrings (x:xs) = slist z ++ all_substrings xs
where z = x:xs
λ> all_substrings "1234"
["1234","123","12","1","234","23","2","34","3","4"]

Rotate a list in Haskell

I have a list a defined,
let a = ["#","#","#","#"]
How can I rotate the # two spaces, so that it ends up like this?
["#","#","#","#"]
I thought this might work,
map last init a
but maybe the syntax has to be different, because map can only work with one function?
For completeness's sake, a version that works with both empty and infinite lists.
rotate :: Int -> [a] -> [a]
rotate _ [] = []
rotate n xs = zipWith const (drop n (cycle xs)) xs
Then
Prelude> rotate 2 [1..5]
[3,4,5,1,2]
A simple solution using the cycle function, which creates an infinite repetition of the input list:
rotate :: Int -> [a] -> [a]
rotate n xs = take (length xs) (drop n (cycle xs))
then
> rotate 2 ["#","#","#","#"]
["#","#","#","#"].
Why make it complicated?
rotate n xs = bs ++ as where (as, bs) = splitAt n xs
rotate :: Int -> [a] -> [a]
rotate = drop <> take
Because of the instance Monoid b => Monoid (a -> b) instance the above is equivalent to
rotate n = drop n <> take n
and that is in turn equivalent to
rotate n xs = drop n xs <> take n xs
because of the instance Monoid d => Monoid (c -> d) instance, which is equivalent to
rotate n xs = drop n xs ++ take n xs
because of the instance Monoid [e] instance (with b ~ c -> d and d ~ [e]).
(well, Semigroup is enough, but that's the same, here).
I'm very new to haskell, so the MGwynne's answer was easy to understand. Combined with the comment suggesting an alternative syntax, I tried to make it work in both directions.
rotate :: Int -> [a] -> [a]
rotate n xs = take lxs . drop (n `mod` lxs) . cycle $ xs where lxs = length xs
So rotate (-1) [1,2,3,4] gives you the same result as rotate 3 [1,2,3,4].
I thought that I had to add this because dropping less than 0 elements does nothing, so my preferred answer gives "wrong" (at least confusing) results with negative values for the n parameter.
The interesting part of this solution is that it combines "completeness" for negative rotations with the handling of empty lists. Thanks to Haskell's laziness, it also gives correct results for rotate 0 [].
Beginner attempt:
myRotate :: Int -> [String] -> [String]
myRotate 0 xs = xs
myRotate n xs = myRotate (n-1) (last xs : init xs)
Not very fast for large lists, but adequate:
rotate :: Int -> [a] -> [a]
rotate n xs = iterate rot xs !! n
where
rot xs = last xs : init xs
For example:
> rotate 2 ["#","#","#","#"]
["#","#","#","#"]
rotate :: Int -> [a] -> [a]
rotate n xs = drop k xs ++ take k xs
where k = length xs - n
This function rotates by n places to the right.

Remove every nth element from string

How can you remove every nth element of a string?
I'm guessing you would use the drop function in some kind of way.
Like this drops the first n, how can you change this so only drops the nth, and then the nth after that, and so on, rather than all?
dropthem n xs = drop n xs
Simple. Take (n-1) elements, then skip 1, rinse and repeat.
dropEvery _ [] = []
dropEvery n xs = take (n-1) xs ++ dropEvery n (drop n xs)
Or in showS style for efficiency's sake
dropEvery n xs = dropEvery' n xs $ []
where dropEvery' n [] = id
dropEvery' n xs = (take (n-1) xs ++) . dropEvery n (drop n xs)
-- groups is a pretty useful function on its own!
groups :: Int -> [a] -> [[a]]
groups n = map (take n) . takeWhile (not . null) . iterate (drop n)
removeEveryNth :: Int -> [a] -> [a]
removeEveryNth n = concatMap (take (n-1)) . groups n
remove_every_nth :: Int -> [a] -> [a]
remove_every_nth n = foldr step [] . zip [1..]
where step (i,x) acc = if (i `mod` n) == 0 then acc else x:acc
Here's what the function does:
zip [1..] is used to index all items in the list, so e.g. zip [1..] "foo" becomes [(1,'f'), (2,'o'), (3,'o')].
The indexed list is then processed with a right fold which accumulates every element whose index is not divisible by n.
Here's a slightly longer version that does essentially the same thing, but avoids the extra memory allocations from zip [1..] and doesn't need to calculate modulus.
remove_every_nth :: Int -> [a] -> [a]
remove_every_nth = recur 1
where recur _ _ [] = []
recur i n (x:xs) = if i == n
then recur 1 n xs
else x:recur (i+1) n xs
Try to combine take and drop to achieve this.
take 3 "hello world" = "hel"
drop 4 "hello world" = "o world"
I like the following solution:
del_every_nth :: Int -> [a] -> [a]
del_every_nth n = concat . map init . group n
You just have to define a function group which groups a list in portions of length n. But that's quite easy:
group :: Int -> [a] -> [[a]]
group n [] = []
group n xs = take n xs : group n (drop n xs)

Resources