How can I group a list into smaller lists of equal length (except last sublist) in haskell?
E.g.
sublist 3 [1,2,3,4,5,6,7,8] -> [[1,2,3],[4,5,6],[7,8]]
sublist 2 [4,1,6,1,7,3,5,3] -> [[4,1],[6,1],[7,3],[5,3]]
Try:
import Data.List.Split
> splitEvery 2 [4,1,6,1,7,3,5,3]
[[4,1],[6,1],[7,3],[5,3]]
If you want to stick to prelude, you can pull this off using splitAt.
splitEvery _ [] = []
splitEvery n list = first : (splitEvery n rest)
where
(first,rest) = splitAt n list
The Data.List.Split module has a chunksOf function for this:
Prelude> import Data.List.Split
Prelude Data.List.Split> chunksOf 3 [1,2,3,4,5,6,7,8,9,10]
[[1,2,3],[4,5,6],[7,8,9],[10]]
Prelude Data.List.Split> chunksOf 3 []
[]
It seemed to be installed by default on my machine, but you might need to get it with cabal.
Another solution that I like is:
splitEvery :: Int -> [a] -> [[a]]
splitEvery n = takeWhile (not.null) . map (take n) . iterate (drop n)
Yet another solution:
split :: Int -> [a] -> [[a]]
split n = unfoldr (\s -> if null s then Nothing else Just $ splitAt n s)
I know this is old, but since this seems to be a post for people who are fairly new to Haskell, I felt like posting my solution too. I tried to solve this problem by using Prelude, only:
sublist :: Int -> [a] -> [[a]]
sublist n ls
| n <= 0 || null ls = []
| otherwise = take n ls:sublist n (drop n ls)
Testing
sublist 3 [1,2,3,4,5,6] -- λ> [[1,2,3], [4,5,6]]
sublist 5 [1,2,3] -- λ> [[1,2,3]]
sublist (-1) [1,2,3] -- λ> []
sublist 20 [] -- λ> []
This list comprehension uses tails. Since the first set starts with one, all subsequent subsets start with an odd number.
ts n ls = [take n l|l<-init$tails ls,odd (head l)]
n is the size-of-sublist, ls is the source list.
The next one will take any list and include unmatched elements. It is set up to do pairs only. It is obvious how to parameterize it to do any chunk size.
np ls = [take 2 (drop a ls)|a<-[0,2..(length ls)-1]]
Just include an n as a parameter and replace the 2's in the formula, one after take and one after 0 in the generator.
Related
Here is the list of lists: [[1,2,3],[1,2,3,4],[1,2,3]]
How can I increment each element of the second list by the length of the first list, and increment the third list by the length of the first list + second list? The first list should remain unchanged.
Intended output: [[1,2,3],[4,5,6,7],[8,9,10]]
Since the first list has length 3, the second list is generated by [1+3, 2+3, 3+3, 4+3].
Since the first list + second list combined have length 7, the third list is generated by [1+7, 2+7, 3+7].
Ideally it should work with any number of lists.
So far, I've had slight sucess using this:
scanl1 (\xs ys -> [y + length xs | y <- ys]) [[1,2,3],[1,2,3,4],[1,2,3]]
which outputs: [[1,2,3],[4,5,6,7],[5,6,7]]
scanl1 is a good idea, but it's not quite right, because you don't want your accumulator to be a list, but rather to be an integer. So you really want scanl, not scanl1. I'll leave it as an exercise for you to see how to adjust your solution - given that you managed to write something almost-right with scanl1, I don't think you'll find it too hard once you have the right function.
In the comments, jpmariner suggests mapAccumL :: (s -> a -> (s, b)) -> s -> [a] -> (s, [b])). That's perfectly typed for what we want to do, so let's see how it would look.
import Data.Traversable (mapAccumL)
addPreviousLengths :: [[Int]] -> [[Int]]
addPreviousLengths = snd . mapAccumL go 0
where go n xs = (n + length xs, map (+ n) xs)
λ> addPreviousLengths [[1,2,3],[1,2,3,4],[1,2,3]]
[[1,2,3],[4,5,6,7],[8,9,10]]
mapAccumL really is the best tool for this job - there's not much unnecessary complexity involved in using it. But if you're trying to implement this from scratch, you might try the recursive approach Francis King suggested. I'd suggest a lazy algorithm instead of the tail-recursive algorithm, though:
incrLength :: [[Int]] -> [[Int]]
incrLength = go 0
where go _ [] = []
go amount (x:xs) =
map (+ amount) x : go (amount + length x) xs
It works the same as the mapAccumL version. Note that both versions are lazy: they consume only as much of the input list as necessary. This is an advantage not shared by a tail-recursive approach.
λ> take 3 . incrLength $ repeat [1]
[[1],[2],[3]]
λ> take 3 . addPreviousLengths $ repeat [1]
[[1],[2],[3]]
There are many ways to solve this. A simple recursion is one approach:
lst :: [[Int]]
lst = [[1,2,3],[1,2,3,4],[1,2,3]]
incrLength :: [[Int]] -> Int -> [[Int]] -> [[Int]]
incrLength [] _ result = result
incrLength (x:xs) amount result =
incrLength xs (amount + length x) (result ++ [map (+amount) x])
(Edit: it is more efficient to use (:) in this function. See #amalloy comment below. The result then has to be reversed.
incrLength :: [[Int]] -> Int -> [[Int]] -> [[Int]]
incrLength [] _ result = reverse result
incrLength (x:xs) amount result =
incrLength xs (amount + length x) (map (+amount) x : result)
End Edit)
Another approach is to use scanl. We use length to get the length of the inner lists, then accumulate using scanl.
map length lst -- [3,4,3]
scanl (+) 0 $ map length lst -- [0,3,7,10]
init $ scanl (+) 0 $ map length lst -- [0,3,7]
Then we zip the lst and the accumulated value together, and map one over the other.
incrLength' :: [[Int]] -> [[Int]]
incrLength' lst =
[map (+ snd y) (fst y) | y <- zip lst addlst]
where
addlst =init $scanl (+) 0 $ map length lst
main = do
print $ incrLength lst 0 [] -- [[1,2,3],[4,5,6,7],[8,9,10]]
I am pretty new to Haskell. I am trying to write a program that takes a list and returns a list of one copy of the first element of the input list, followed by two copies of the second element, three copies of the third, and so on. e.g. input [1,2,3,4], return [1,2,2,3,3,3,4,4,4,4].
import Data.List
triangle :: [a] -> [a]
triangle (x:xs)
|x/=null = result ++ xs
|otherwise = group(sort result)
where result = [x]
I try to use ++ to add each list into a new list then sort it, but it does not work. What I tried to achieve is, for example: the list is [1,2,3], result = [1,2,3]++[2,3]++[3] but sorted.
here is a short version
triangle :: [a] -> [a]
triangle = concat . zipWith replicate [1..]
How it works
zipWith takes a function f : x -> y -> z and two lists [x1,x2,...] [y1,y2,..] and produces a new list [f x1 y1, f x2 y2, ...]. Both lists may be infinite - zipWith will stop as soon one of the list run out of elements (or never if both are infinite).
replicate : Int -> a -> [a] works like this: replicate n x will produce a list with n-elements all x - so replicate 4 'a' == "aaaa".
[1..] = [1,2,3,4,...] is a infinite list counting up from 1
so if you use replicate in zipWith replicate [1..] [x1,x2,...] you get
[replicate 1 x1, replicate 2 x2, ..]
= [[x1], [x2,x2], ..]
so a list of lists - finally concat will append all lists in the list-of-lists together to the result we wanted
the final point: instead of triangle xs = concat (zipWith replicate [1..] xs) you can write triangle xs = (concat . zipWith repliate [1..]) xs by definition of (.) and then you can eta-reduce this to the point-free style I've given.
Here you go:
triangle :: [Int] -> [Int]
triangle = concat . go 1
where
go n [] = []
go n (x:xs) = (replicate n x) : (go (n+1) xs)
update: now I see what you mean here. you want to take diagonals on tails. nice idea. :) Here's how:
import Data.Universe.Helpers
import Data.List (tails)
bar :: [a] -> [a]
bar = concat . diagonals . tails
That's it!
Trying it out:
> concat . diagonals . tails $ [1..3]
[1,2,2,3,3,3]
Or simply,
> diagonal . tails $ [11..15]
[11,12,12,13,13,13,14,14,14,14,15,15,15,15,15]
(previous version of the answer:)
Have you heard about list comprehensions, number enumerations [1..] and the zip function?
It is all you need to implement your function:
foo :: [a] -> [a]
foo xs = [ x | (i,x) <- zip [1..] xs, j <- .... ]
Can you see what should go there instead of the ....? It should produce some value several times (how many do we need it to be?... how many values are there in e.g. [1..10]?) and then we will ignore the produced value, putting x each time into the resulting list, instead.
I have such code for creating permutations:
--unique permutation
perm :: [t] -> [[t]]
perm [] = [[]]
perm (x:xs) = [(y:zs) | (y,ys) <- views (x:xs), zs <- perm ys]
--create all possible views
views :: [t] -> [(t,[t])]
views [] = []
views (x:xs) = ((x,xs) : [ (y,(x:ys)) | (y,ys) <- views xs ])
However I want to limit the output to a certain length. For example, it should take a parameter specifying the number of elements in the ouput of the permutation. I want to create k distinct permutations drawn from a list [0..9].
So, for example, if k will be equal to 3, then the output should be something like this:[1,2,3], [9,8,7], [0,6,8] etc..
Right now if i pass [0..9] to the function it will generate a list with permutations of length 10. I am struggling to come up with a solution.
In the end, the function should look like perm k list
Thank you!
It is connected with this question: Verbal Arithmetics in Haskell (SEND + MORE = MONEY)
Do you mean something like this?
import Data.List (permutations)
choose n list = concatMap permutations $ choose' list [] where
choose' [] r = if length r == n then [r] else []
choose' (x:xs) r | length r == n = [r]
| otherwise = choose' xs (x:r)
++ choose' xs r
Output:
*Main> choose 2 [0..5]
[[1,0],[0,1],[2,0],[0,2],[3,0],[0,3],[4,0],[0,4],[5,0],[0,5],[2,1]
,[1,2],[3,1],[1,3],[4,1],[1,4],[5,1],[1,5],[3,2],[2,3],[4,2],[2,4]
,[5,2],[2,5],[4,3],[3,4],[5,3],[3,5],[5,4],[4,5]]
Will replicateM do what you need?
Prelude Control.Monad> take 10 $ replicateM 3 [0..9]
[[0,0,0],[0,0,1],[0,0,2],[0,0,3],[0,0,4],[0,0,5],[0,0,6],[0,0,7],[0,0,8],[0,0,9]]
Prelude Control.Monad> take 10 $ replicateM 4 [1,3,3,7]
[[1,1,1,1],[1,1,1,3],[1,1,1,3],[1,1,1,7],[1,1,3,1],[1,1,3,3],[1,1,3,3],[1,1,3,7],[1,1,3,1],[1,1,3,3]]
Prelude Control.Monad> take 10 $ replicateM 2 [4,2]
[[4,4],[4,2],[2,4],[2,2]]
Can anyone help me to generate all the subsets of a given set?
Example:If I have [2,3,4] and if I want K=2, that means I need pairs of two => [[2,3], [3,2], [2,4], [4,2], [3,4], [4,3]]
I wrote this code, but it generates only the number of subsets:
arrange::Int->Int->Int
arrange n 1=n
arrange n r=n*arrange (n-1) (r-1)
Another version, but this doesn't generate all solutions of the subsets:
arrange 0 _ =[[]]
arrange _ []=[]
arrange n (x:xs)=(map(x:)) (arrange (n-1) xs)++
(arrange n xs)
Well based on your example this is a possible solution:
import Data.List (permutations)
pick :: Int -> [a] -> [[a]]
pick 0 _ = [[]]
pick _ [] = []
pick n (x:xs) = map (x:) (pick (n-1) xs) ++ pick n xs
arrange :: Int -> [a] -> [[a]]
arrange n = concatMap permutations . pick n
example
λ> arrange 2 [2,3,4]
[[2,3],[3,2],[2,4],[4,2],[3,4],[4,3]]
as you can see the trick is just picking a number of elements and then getting all permutations of the results (using concatMap to concat them together)
of course this might be homework so you might want to implement permutations by yourself ;)
It's well known that the powerset of a list:
{1,2,3,4} is {{},{1},{2},{1,2},{3},{1,3},{2,3},{1,2,3},{4},{1,4},{2,4},{1,2,4},{3,4},{1,3,4},{2,3,4},{1,2,3,4}}
the haskell code I got for that problem is:
potencia [] = [[]]
potencia (a:bs) = potencia bs ++ map (a:) (potencia bs)
Now, how would I get a list of sublists of the same length?, for example, the list above would generate the next list of sublists of length 3 = {{1,2,3},{1,2,4},{1,3,4}}
I'm a student sorry for my english, thanks in advance... XD
How about
sublists _ 0 = [[]]
sublists [] _ = []
sublists (x:xs) n = sublists xs n ++ map (x:) (sublists xs $ n - 1)
Which is very similar to the code you had but just has two decreasing parameters, the length and the list.
Also, for more advanced Haskellers
powerset = flip runCont id . foldM step [[]]
where step xs x = cont $ \c -> c xs ++ c (map (x:) xs)
is a powerset implementation without recursion using continuations. Doing the same with the sublists function is an interesting challenge.
I'm thinking just
subsequencesOf :: Int -> [a] -> [[a]]
subsequencesOf n = filter ((== n) . length) . subsequences
Which will give you
> subsequencesOf 3 [1, 2, 3, 4]
[[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
Although I find it weird that this isn't an operation in Data.Set, and that Set isn't a monad (and therefore has its own version of replicateM.) I guess there might be obstacles in the way there.