I want to create one function that returns a list of all possible ways of splitting a list into two non-empty parts.
split :: [([a], [a])]
For example:
> split [1,2,3,4]
> [ ([1], [2,3,4]), ([1,2], [3,4]), ([1,2,3], [4]) ]
I'm far away from the solution. Can anyone help me?
Here is another approach using inits and tails:
Let xs = [1,2,3,4]. Note:
import Data.List
inits xs -- returns: [[] , [1], [1,2], [1,2,3], [1,2,3,4]]
tails xs -- returns: [[1,2,3,4], [2,3,4], [3,4], [4] , []]
So zipping these two lists together give you all the ways of splitting the list into two parts:
zip (inits xs) (tails xs)
= [ ([], [1,2,3,4]),
([1], [2,3,4] ),
([1,2], [3,4]) ,
([1,2,3,4], []) ]
If you don't want the first and last pairs, just trim appropriately:
split xs = init $ tail $ zip (inits xs) (tails xs)
If you wanted to implement this yourself not using library functions
splits :: [a] -> [([a],[a])]
splits [] = []
splits xx = splits' ([],xx)
where splits' :: ([a],[a]) -> [([a],[a])]
splits' xy#(x,[]) = [xy]
splits' xy#(x,y:yy) = let z = (x++[y],yy)
in xy:splits' z
Sure, that's easy using map, splitAt and flip.
First do import Data.List
let split x = map (flip splitAt x) [1..length x-1]
result:
split [1,2,3,4]
[([1],[2,3,4]),([1,2],[3,4]),([1,2,3],[4])]
Explanation of flip - We are using map and flip to generate results in this example
[splitAt 1 x, splitAt 2 x, splitAt 3 x]
Flip simply allows us to flip the expected arguments. Otherwise we could have written a lambda like so:
let split x = map (\z -> splitAt z x) [1..length x-1]
another approach with iterate
split (x:xs) = takeWhile (not . null . snd) $ iterate (\(x,(y:ys)) -> (x++[y],ys)) ([x], xs)
Related
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.
A list of integers is given. Determine whether the list contains the same numbers that follow one after another. Return the index of the first repeated number or -1 if there are no repetitions.
The function should output:
duplicateIndex [1,8,3,3,4] -> 2
duplicateIndex [7,7,3,2,5] -> 0
duplicateIndex [1,2] -> -1
I tried to solve as follows, but this solution is not correct!
let duplicateIndex lst = [if x ==y then lst !!x else (-1) | x:ys <- tails lst, y <- ys]
Help me fix the code.
Your list comprehension expression returns a list element rather than a list index (as specified). Furthermore, there is nothing to keep track of the current index value.
If we look for a solution that is easy to visualize, we can try using zip. When it is about comparing 2 adjacent elements, it is common to use zip xs (tail xs) as an auxiliary list.
But that still does not include any information about indexes. For this, we have to add the index sequence as [0..].
As ultimately we aim to return an index, an interesting list comprehension expression would start like:
[ ... | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], ... constraints ... ]
Let's see what our auxiliary list looks like:
λ>
λ> printAsLines ys = mapM_ (putStrLn . show) ys
λ>
λ> xs = [1,8,3,3,4,7,5,5,2]
λ>
λ> printAsLines $ zip (zip xs (tail xs)) [0..]
((1,8),0)
((8,3),1)
((3,3),2)
((3,4),3)
((4,7),4)
((7,5),5)
((5,5),6)
((5,2),7)
λ>
Furthermore, looking for a repeated number we need to have x == y as a constraint; and we want to return an index, so the left side of the list comprehension has to be idx. This gives:
[ idx | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], x == y ]
Let's test it:
λ>
λ> [ idx | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], x == y ]
[2,6]
λ>
So we're almost done: we just need to take the first element of the last list comprehension, assuming of course there is a first element at all. Otherwise, return -1.
This gives the following code:
duplicateIndex :: Eq α => [α] -> Int
duplicateIndex xs =
let indexes = [ idx | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], x == y ]
in
if (null indexes) then (-1)
else head indexes
The language lazyness ensures that the indexes list will not be evaluated beyond finding the first element.
EDIT:
The function can be written in more compact fashion using zip3:
duplicateIndex :: Eq α => [α] -> Int
duplicateIndex xs =
let idxs = [ idx | (x, y, idx) <- zip3 xs (tail xs) [0..], x == y ]
in if (null idxs) then (-1) else (head idxs)
Consider this list of tuples:
[(57,48),(58,49),(59,50),(65,56),(65,47),(65,57),(65,49), (41, 11)]
I want to remove a tuple (a, b) if its second element b is equal to the first element of another tuple and all the tuples with the same a that come after it. For example:
The second element of (65,57) is 57 and the first tuple in the list (57,48)has 57 as its first element, so (65,57) should be removed and all tuples that come after it that start with 65, namely (65,49). The tuples that come before it, (65,56) and (65,47), should stay in the list.
Does anyone have an idea how to do this?
For efficiency (single pass), you should create two sets, one for elements you've seen as the first elements of tuples, the other for elements you've seen both as first and second elements (ie. delete if matches first element).
Something like,
{-# LANGUAGE PackageImports #-}
import "lens" Control.Lens (contains, (.~), (^.), (&))
import "yjtools" Data.Function.Tools (applyUnless, applyWhen)
import qualified "containers" Data.IntSet as Set
filterTuples :: Foldable t => t (Int, Int) -> [(Int, Int)]
filterTuples = flip (foldr go $ const []) (Set.empty, Set.empty)
where
go p#(x,y) go' (fsts, deletes) =
let seenFst = fsts ^. contains y
shouldDelete = seenFst || deletes ^. contains x
fsts' = fsts & contains x .~ True
deletes' = deletes & applyWhen seenFst (contains y .~ True)
in applyUnless shouldDelete (p:) $ go' (fsts', deletes')
EDITs: for correctness, clarity, spine-laziness
You could start by creating a distinct set of all the first elements, e.g.:
Prelude Data.List> firsts = nub $ fst <$>
[(57,48),(58,49),(59,50),(65,56),(65,47),
(65,57),(65,49), (41, 11)]
Prelude Data.List> firsts
[57,58,59,65,41]
You could use break or span as Robin Zigmond suggests. You'll need a predicate for that. You could use elem, like this:
Prelude Data.List> elem 48 firsts
False
Prelude Data.List> elem 49 firsts
False
...
Prelude Data.List> elem 57 firsts
True
If you're concerned that elem is too inefficient, you could experiment with creating a Set and use the member function instead.
Perhaps try using mapAccumL starting with the initial list as the accumulator. Then maintain a Predicate as a parameter too which acts as a decider for what has been seen, and this will determine if you can output or not at each step in the traversal.
I'm an absolute beginner in haskell, so there probably is a much more elegant/efficient solution for this. But anyways I wanted to share the solution I came up with:
filterTuples :: [(Int, Int)] -> [(Int,Int)]
filterTuples [] = []
filterTuples (x:xs) = x:filterTuples(concat ((fst temp) : [filter (\z -> fst z /= del) (snd temp)]))
where del = fst (head (snd temp))
temp = break (\y -> (snd y == fst x)) xs
(Glad for feedback on how to improve this)
f consumes a list of pairs: xs; it produces a new list of pairs: ys. ys contains every pair: (a, b) in xs, except the pair whose second element b: previously occurred as first elements: a. When such a pair: (a, b) is encountered, subsequent pairs that have a as their first elements are excluded from ys.
f xs = go xs [] []
where
go [] ys zs = ys
go (x#(a,b):xs) ys zs
| b `elem` as = go xs ys (a:zs)
| a `elem` zs = go xs ys zs
| otherwise = [x] ++ go xs ys zs
as = (nub . fst . unzip) xs
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.
Data.Lists.Split is actually not working winHugs interpreter. which can be get by splitEvery 3 ['a'..'z'] function
is it possible to achieve this without Data.Lists.Split ?
list of separate integers [5,5,5,6,6,6] -> to be [555,666] to concat every three numbers !
should be [Int]->[Int]
Yes, it's quite possible. You can proceed like this:
First write a function that takes three digits and "concat"s them into one number (this is quite easy using multiplication and addition).
Then you write another function which takes a list and processes its elements in threes using the previous function. Basically the definition of that function will look like the definition of map, except that you process three elements instead of one in the non-empty case (i.e. you use a pattern like x1:x2:x3:xs), and you call the previously defined function instead of one given as an argument.
Here's an implementation of splitEvery that should work for your purposes:
import Data.List
splitEvery _ [] = []
splitEvery n xs = chunk : splitEvery n remaining
where (chunk, remaining) = splitAt n xs
Let's make a general function that groups a given number of items, and applies a given function to each group.
groupMap :: ([a] -> b) -> Int -> [a] -> [b]
groupMap f n xs = go xs
where go [] = []
go xs = f (take n xs) : go (drop n xs)
OK, now what f should we pass in?
intListToInt :: [Int] -> Int
intListToInt xs = go xs 0
where go [] v = v
go (x:xs) v = go xs (x + v*10)
There are various different ways you could write this; I'm experimenting with the workhorse helper technique. Note that this type signature lines up nicely with the first argument of groupMap. Anyways...let's see if it works!
ghci> groupMap intListToInt 3 [5,5,5,6,6,6]
[555,666]
Yay! It even works for other stuff too. (some sketchy uses follow...)
ghci> groupMap (read :: String -> Int) 5 "1234554321"
[12345,54321]
ghci> groupMap (read :: String -> Bool) 4 "TrueTrueTrue"
[True,True,True]
ghci> groupMap sum 2 [1,2,3,4,5,6]
[3,7,11]
NB: If I'm not mistaken, intListToInt could benefit from a little more strictness:
{-# LANGUAGE BangPatterns #-}
intListToInt xs = go xs 0
where go [] !v = v
go (x:xs) !v = go xs (x + v*10)
Though I'm not at all familiar with which language pragmas Hugs supports.
Use show, concat and read:
map (read . (>>= show)) . splitEvery 3
Possible Solution:
Here is one possible solution, using only function from the Prelude:
group3 :: [Int] -> [Int]
group3 [] = []
group3 xs = toSingleNum (take 3 xs): (group3 (drop 3 xs))
where toSingleNum ys = read $ concat $ map show ys
There are, of course, innumerable ways to do this. This is one.
Explanation:
group3 works by using the take and drop functions and natural recursion to split the list into groups of 3, and applying toSingleNum to each of the groups.
Ignoring the application of take and drop, the function works roughly as below:
group3 [1,2,3,4,5,6,7,8,9]
toSingleNum [1,2,3] : group3 [4,5,6,7,8,9]
toSingleNum [1,2,3] : toSingleNum [4,5,6] : group3 [7,8,9]
toSingleNum [1,2,3] : toSingleNum [4,5,6] : toSingleNum [7,8,9] : group3 []
toSingleNum [1,2,3] : toSingleNum [4,5,6] : toSingleNum [7,8,9] : []
After toSingleNum is applied, we'd have:
123 : 456 : 789 : []
[123, 456, 789]
toSingleNum converts a list of numbers into a single number.
toSingleNum [1, 3, 4]
>>> 134
toSingleNum [12, 13, 14]
>>> 121314
The conversion in toSingleNum is done by converting the numbers to a String, then combining them, then converting back to a number.
toSingleNum [1, 3, 4]
read $ concat $ map show [1, 3, 4]
read $ concat $ ["1", "3", "4"]
read $ "134"
134
Further Reading:
If you're interested in Haskell, I'd recommend Graham Hutton's excellent "Programming in Haskell", or one of the tutorials listed on the Haskell Wiki.
First, split the list into chunks:
chunk n = unfoldr split
where
split [] = Nothing -- stop
split xs = Just $ splitAt n xs -- keep going
ghci> chunk 3 [1..6]
[[1,2,3],[4,5,6]]
The chunk function continues chopping n-sized chunks off the input list, until the list is empty. (unfoldr is one of the most under-appreciated functions in the standard library, by the way.)
Then turn each chunk into a number:
cumulate = foldl' (\x y -> x * 10 + y) 0
ghci> cumulate [4,5,6]
456
Now, compose these two functions together:
coalesce = map cumulate . chunk
ghci> coalesce [5,5,5,6,6,6]
[555,666]