# 99 questions/Solutions/20

### From HaskellWiki

< 99 questions | Solutions(Difference between revisions)

m (One of removeAt examples were removing element at wrong index (off-by-one)) |
|||

(3 intermediate revisions by 3 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 | ||

Line 17: | Line 17: | ||

<haskell> | <haskell> | ||

removeAt n xs = (xs !! (n - 1), take (n - 1) xs ++ drop n xs) | 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 59: | 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

splitAt

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