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'm trying to solve the following problem found in "Introduction to functional programming" First edition Bird-Wadler.
5 .6.2 The function choose k xs returns a list of all subsequences of xs whose
length is exactly k. For example:
? choose 3 "list"
["ist" , "lst" , "lit" , "lis"]
Give a recursive definition of choose. Show that if xs has length n then
choose k xs has length nk
I only could come up with a non-recursive solution based on a function that returns the list of subsets of an array:
subs :: [a] -> [[a]]
subs [] = [[]]
subs (x:xs) = subs xs ++ map (x:) (subs xs)
choose :: Int -> [a] -> [[a]]
choose x = filter ((== x) . length) . subs
I think you are asking:
What is a lone, recursive function solution to this problem?
These problems usually can be solved if you mentally walk through the base and recursive cases carefully. For example:
Choose is a function from ints and list of values to a list of lists of values:
choose :: Int -> [a] -> [[a]]
If the result is supposed to be 0 length then there is exactly one sublist of said length:
choose 0 _ = [ [] ]
If the result is non-zero but we have no more characters with which to make a sublist then there are no solutions:
choose _ [] = []
Otherwise we can take the first character and append that to all solutions of length one shorter:
choose n (x : xs) =
map (x :) (choose (n - 1) xs)
Or we discard this character (ex, drop 'l' and get the result "ist") and look for a solution with the substring:
++ choose n xs
Given an integer n, how can I build the list containing all lists of length n^2 containing exactly n copies of each integer x < n? For example, for n = 2, we have:
[0,0,1,1], [0,1,0,1], [1,0,0,1], [0,1,1,0], [1,0,1,0], [1,1,0,0]
This can be easily done combining permutations and nub:
f :: Int -> [[Int]]
f n = nub . permutations $ concatMap (replicate n) [0..n-1]
But that is way too inefficient. Is there any simple way to encode the efficient/direct algorithm?
Sure, it's not too hard. We'll start with a list of n copies of each number less than n, and repeatedly choose one to start our result with. First, a function for choosing an element from a list:
zippers :: [a] -> [([a], a, [a])]
zippers = go [] where
go l (h:r) = (l,h,r) : go (h:l) r
go _ [] = []
Now we'll write a function that produces all possible interleavings of some input lists. Internally we'll maintain the invariant that each [a] is non-empty; hence we'll have to establish that invariant before we start recursing. In fact, this will be wasted work in the way we intend to call this function, but for good abstraction we might as well handle all inputs correctly, right?
interleavings :: [[a]] -> [[a]]
interleavings = go . filter (not . null) where
go [] = [[]]
go xss = do
(xssl, x:xs, xssr) <- zippers xss
(x:) <$> interleavings ([xs | not (null xs)] ++ xssl ++ xssr)
And now we're basically done. All we have to do is feed in an appropriate starting list.
f :: Int -> [[Int]]
f n = interleavings (replicate n <$> [1..n])
Try it in ghci:
> f 2
[[1,1,2,2],[1,2,2,1],[1,2,1,2],[2,2,1,1],[2,1,1,2],[2,1,2,1]]
Lets say I have a list with elements, for example [1,2,3,4,5,6,7,8].
I want to create all permutations of this elements with length N.
So, for N = 4 it will be
[[1,1,1,1],[1,1,1,2],[1,1,2,1],[1,2,1,1],[2,1,1,1],..] and so on.
comb :: Int -> [a] -> [[a]]
comb 0 _ = [[]]
comb _ [] = []
comb m (x:xs) = map (x:) (comb (m-1) xs) ++ comb m xs
Now, to get this lists first I find all combinations with repetitions for my list,
so [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,1,4],[1,1,1,5],...] and for each list I find all permutations and if permutation is not in the list I add it to the list.
permutations1 :: Eq a => [a] -> [[a]]
permutations1 [] = [[]]
permutations1 list = [(x:xs) | x <- list, xs <- permutations1 $ delete1 x list]
delete1:: Eq a => a -> [a] -> [a]
delete1 _ [] = []
delete1 a (b:bc) | a == b = bc
| otherwise = b : delete1 a bc
And that's how I get wanted answer.
I understand that it is really(really) bad, but I don't understand haskell enough to write function that will combine these functions.
That is called sampling with replacement. In haskell you may utilize replicateM and monadic behaviour of lists (i.e. non-deterministic computations)
\> import Control.Monad (replicateM)
\> length $ replicateM 4 [1..5] -- should output 5^4
625
\> replicateM 4 [1..5]
[[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,1,4],[1,1,1,5],[1,1,2,1],[1,1,2,2],[1,1,2,3],[1,1,2,4],[1,1,2,5]] ....
If you want to have a sample of size 4 from a population of size 5 with replacement, then for each of the 4 items you have 5 choices; so you are replicating each of the [1..5] 4 times, hence replicateM 4.
The Monad type class (i.e. the M part) says that you should be able to bind these intermediate values together.
The list instance of monad type class models non-determinism. i.e it says that each item is non-deterministic but it can be one of [1..5] values, and to bind them together take an outer product of all the non-deterministic values; because if you have 4 items each taking 5 possible values then you have 5^4 possible final outputs.
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.