https://wiki.haskell.org/api.php?action=feedcontributions&user=Alatar224&feedformat=atomHaskellWiki - User contributions [en]2024-03-28T23:54:53ZUser contributionsMediaWiki 1.35.5https://wiki.haskell.org/index.php?title=99_questions/Solutions/18&diff=3679299 questions/Solutions/182010-09-17T14:47:45Z<p>Alatar224: added a cleaner version of the final solution</p>
<hr />
<div>(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and k'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
The same solution as above, but the more paranoid (maybe too paranoid?) version of it (uses guards and Maybe):<br />
<br />
<haskell><br />
slice :: [a] -> Int -> Int -> Maybe [a]<br />
slice [] _ _ = Just []<br />
slice xs k n | k == n = Just []<br />
| k > n || k > length xs || n > length xs || k < 0 || n < 0 = Nothing<br />
| k == 0 = Just (take n xs)<br />
| otherwise = Just (drop (k-1) $ take n xs)<br />
</haskell><br />
<br />
Or, an iterative solution:<br />
<br />
<haskell><br />
slice :: [a]->Int->Int->[a]<br />
slice lst 1 m = slice' lst m []<br />
where<br />
slice' :: [a]->Int->[a]->[a]<br />
slice' _ 0 acc = reverse acc<br />
slice' (x:xs) n acc = slice' xs (n - 1) (x:acc)<br />
slice (x:xs) n m = slice xs (n - 1) (m - 1)<br />
</haskell><br />
<br />
Or:<br />
<br />
<haskell><br />
slice :: [a] -> Int -> Int -> [a]<br />
slice (x:xs) i k<br />
| i > 1 = slice xs (i - 1) (k - 1)<br />
| k < 1 = []<br />
| otherwise = x:slice xs (i - 1) (k - 1)<br />
</haskell><br />
<br />
Another way using <hask>splitAt</hask>, though not nearly as elegant as the <hask>take</hask> and <hask>drop</hask> version:<br />
<br />
<haskell><br />
slice :: [a] -> Int -> Int -> [a]<br />
slice xs i k = chunk<br />
where chop = snd $ splitAt i' xs -- Get the piece starting at i<br />
chunk = fst $ splitAt (k - i') chop -- Remove the part after k<br />
i' = i - 1<br />
</haskell><br />
A little cleaner, using the previous problem's split (a.k.a. <hask>splitAt</hask>):<br />
<haskell><br />
slice xs (i+1) k = snd (split (fst (split xs k)) i)<br />
</haskell></div>Alatar224https://wiki.haskell.org/index.php?title=99_questions/Solutions/9&diff=3677899 questions/Solutions/92010-09-15T17:06:33Z<p>Alatar224: oops mixed up my edge case</p>
<hr />
<div>(**) Pack consecutive duplicates of list elements into sublists.<br />
<br />
If a list contains repeated elements they should be placed in separate sublists.<br />
<br />
<haskell><br />
pack (x:xs) = let (first,rest) = span (==x) xs<br />
in (x:first) : pack rest<br />
pack [] = []<br />
</haskell><br />
<br />
A more verbose solution is<br />
<br />
<haskell><br />
pack :: Eq a => [a] -> [[a]]<br />
pack [] = []<br />
pack (x:xs) = (x:first) : pack rest<br />
where<br />
getReps [] = ([], [])<br />
getReps (y:ys)<br />
| y == x = let (f,r) = getReps ys in (y:f, r)<br />
| otherwise = ([], (y:ys))<br />
(first,rest) = getReps xs<br />
</haskell><br />
<br />
Similarly, using <hask>splitAt</hask> and <hask>findIndex</hask>:<br />
<br />
<haskell><br />
pack :: Eq a => [a] -> [[a]]<br />
pack [] = []<br />
pack (x:xs) = (x:reps) : (pack rest)<br />
where<br />
(reps, rest) = maybe (xs,[]) (\i -> splitAt i xs) (findIndex (/=x) xs)<br />
</haskell><br />
<br />
This is implemented as <hask>group</hask> in <hask>Data.List</hask>.<br />
<br />
Another solution using <hask>takeWhile</hask> and <hask>dropWhile</hask>:<br />
<br />
<haskell><br />
pack :: (Eq a) => [a] -> [[a]]<br />
pack [] = []<br />
pack (x:xs) = (x : takeWhile (==x) xs) : pack (dropWhile (==x) xs)<br />
</haskell></div>Alatar224https://wiki.haskell.org/index.php?title=99_questions/Solutions/9&diff=3677799 questions/Solutions/92010-09-15T16:55:18Z<p>Alatar224: added one more implementation</p>
<hr />
<div>(**) Pack consecutive duplicates of list elements into sublists.<br />
<br />
If a list contains repeated elements they should be placed in separate sublists.<br />
<br />
<haskell><br />
pack (x:xs) = let (first,rest) = span (==x) xs<br />
in (x:first) : pack rest<br />
pack [] = []<br />
</haskell><br />
<br />
A more verbose solution is<br />
<br />
<haskell><br />
pack :: Eq a => [a] -> [[a]]<br />
pack [] = []<br />
pack (x:xs) = (x:first) : pack rest<br />
where<br />
getReps [] = ([], [])<br />
getReps (y:ys)<br />
| y == x = let (f,r) = getReps ys in (y:f, r)<br />
| otherwise = ([], (y:ys))<br />
(first,rest) = getReps xs<br />
</haskell><br />
<br />
Similarly, using <hask>splitAt</hask> and <hask>findIndex</hask>:<br />
<br />
<haskell><br />
pack :: Eq a => [a] -> [[a]]<br />
pack [] = []<br />
pack (x:xs) = (x:reps) : (pack rest)<br />
where<br />
(reps, rest) = maybe ([],xs) (\i -> splitAt i xs) (findIndex (/=x) xs)<br />
</haskell><br />
<br />
This is implemented as <hask>group</hask> in <hask>Data.List</hask>.<br />
<br />
Another solution using <hask>takeWhile</hask> and <hask>dropWhile</hask>:<br />
<br />
<haskell><br />
pack :: (Eq a) => [a] -> [[a]]<br />
pack [] = []<br />
pack (x:xs) = (x : takeWhile (==x) xs) : pack (dropWhile (==x) xs)<br />
</haskell></div>Alatar224