Difference between revisions of "99 questions/Solutions/20"
< 99 questions | Solutions
Jump to navigation
Jump to search
(5 intermediate revisions by 5 users not shown) | |||
Line 6: | Line 6: | ||
[] -> error "removeAt: index too large" |
[] -> error "removeAt: index too large" |
||
x:rest -> (x, front ++ rest) |
x:rest -> (x, front ++ rest) |
||
− | where (front, back) = splitAt k xs |
+ | where (front, back) = splitAt (k - 1) xs |
</haskell> |
</haskell> |
||
− | Simply use the <hask>splitAt</hask> to split after k elements. |
+ | Simply use the <hask>splitAt</hask> to split after k - 1 elements. |
− | If the original list has fewer than k |
+ | If the original list has fewer than k elements, the second list will be empty, and there will be no element to extract. |
− | Note that |
+ | Note that we treat 1 as the first element in the list. |
or |
or |
||
<haskell> |
<haskell> |
||
− | removeAt n xs = (xs!!n,take n xs ++ drop |
+ | removeAt n xs = (xs !! (n - 1), take (n - 1) xs ++ drop n xs) |
+ | </haskell> |
||
+ | |||
+ | or, a safe version of that |
||
+ | |||
+ | <haskell> |
||
+ | removeAt n xs | n > 0 && n <= length xs = (Just (xs !! index), take index xs ++ drop n xs) |
||
+ | | otherwise = (Nothing, xs) |
||
+ | where index = n - 1 |
||
+ | </haskell> |
||
+ | |||
+ | or, a list comprehension based one: |
||
+ | |||
+ | <haskell> |
||
+ | removeAt :: (Enum a) => Int -> [a] -> (a, [a]) |
||
+ | removeAt n xs = ((xs !! (n-1)), [ x | (i, x) <- zip [1..] xs, i /= n ]) |
||
</haskell> |
</haskell> |
||
Line 44: | Line 59: | ||
removeAt :: Int -> [a] -> (a, [a]) |
removeAt :: Int -> [a] -> (a, [a]) |
||
removeAt n xs = let (front, back) = splitAt n xs in (last front, init front ++ back) |
removeAt n xs = let (front, back) = splitAt n xs in (last front, init front ++ back) |
||
+ | </haskell> |
||
+ | |||
+ | Similar, point-free style: |
||
+ | |||
+ | <haskell> |
||
+ | removeAt n = (\(a, b) -> (head b, a ++ tail b)) . splitAt (n - 1) |
||
</haskell> |
</haskell> |
||
Line 53: | Line 74: | ||
where (l, r) = removeAt (n - 1) xs |
where (l, r) = removeAt (n - 1) xs |
||
</haskell> |
</haskell> |
||
+ | |||
+ | |||
+ | [[Category:Programming exercise spoilers]] |
Latest revision as of 11:56, 26 April 2016
(*) Remove the K'th element from a list.
removeAt :: Int -> [a] -> (a, [a])
removeAt k xs = case back of
[] -> error "removeAt: index too large"
x:rest -> (x, front ++ rest)
where (front, back) = splitAt (k - 1) xs
Simply use the splitAt
to split after k - 1 elements.
If the original list has fewer than k elements, the second list will be empty, and there will be no element to extract.
Note that we treat 1 as the first element in the list.
or
removeAt n xs = (xs !! (n - 1), take (n - 1) xs ++ drop n xs)
or, a safe version of that
removeAt n xs | n > 0 && n <= length xs = (Just (xs !! index), take index xs ++ drop n xs)
| otherwise = (Nothing, xs)
where index = n - 1
or, a list comprehension based one:
removeAt :: (Enum a) => Int -> [a] -> (a, [a])
removeAt n xs = ((xs !! (n-1)), [ x | (i, x) <- zip [1..] xs, i /= n ])
Another solution that avoids throwing an error and using ++ operators. Treats 1 as the first element in the list.
removeAt :: Int -> [a] -> (Maybe a, [a])
removeAt _ [] = (Nothing, [])
removeAt 1 (x:xs) = (Just x, xs)
removeAt k (x:xs) = let (a, r) = removeAt (k - 1) xs in (a, x:r)
Another solution that also uses Maybe to indicate failure:
removeAt :: Int -> [a] -> (Maybe a, [a])
removeAt _ [] = (Nothing, [])
removeAt 0 xs = (Nothing, xs)
removeAt nr xs | nr > length xs = (Nothing, xs)
| otherwise = (Just (xs !! nr), fst splitted ++ (tail . snd) splitted)
where splitted = splitAt nr xs
And yet another solution (without error checking):
removeAt :: Int -> [a] -> (a, [a])
removeAt n xs = let (front, back) = splitAt n xs in (last front, init front ++ back)
Similar, point-free style:
removeAt n = (\(a, b) -> (head b, a ++ tail b)) . splitAt (n - 1)
A simple recursive solution:
removeAt 1 (x:xs) = (x, xs)
removeAt n (x:xs) = (l, x:r)
where (l, r) = removeAt (n - 1) xs