From 1474db0eda21343938d045ba808882d7a039405b Mon Sep 17 00:00:00 2001 From: MrBackend Date: Tue, 10 Jan 2017 12:16:34 +0100 Subject: [PATCH] Added insertAt, rewrote splitAt to use new helper --- src/List/Extra.elm | 42 ++++++++++++++++++++++++++++++++++++++++-- tests/Tests.elm | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/List/Extra.elm b/src/List/Extra.elm index 50da941..1cd85bb 100644 --- a/src/List/Extra.elm +++ b/src/List/Extra.elm @@ -23,6 +23,7 @@ module List.Extra , updateIf , updateAt , updateIfIndex + , insertAt , singleton , removeAt , filterNot @@ -81,7 +82,7 @@ module List.Extra {-| Convenience functions for working with List # Basics -@docs last, init, getAt, (!!), uncons, maximumBy, minimumBy, andMap, andThen, takeWhile, dropWhile, unique, uniqueBy, allDifferent, allDifferentBy, replaceIf, setAt, remove, updateIf, updateAt, updateIfIndex, singleton, removeAt, filterNot, swapAt, stableSortWith +@docs last, init, getAt, (!!), uncons, maximumBy, minimumBy, andMap, andThen, takeWhile, dropWhile, unique, uniqueBy, allDifferent, allDifferentBy, replaceIf, setAt, remove, updateIf, updateAt, updateIfIndex, insertAt, singleton, removeAt, filterNot, swapAt, stableSortWith # List transformations @docs intercalate, transpose, subsequences, permutations, interweave @@ -487,6 +488,15 @@ updateIfIndex predicate update list = list +{-| Insert an element at given index +-} +insertAt : Int -> a -> List a -> List a +insertAt index value list = + splitAtWithReversedInit index [] list + |> Tuple.mapSecond ((::) value) + |> uncurry appendUsingReversedInit + + {-| Remove the first occurrence of a value from a list. -} remove : a -> List a -> List a @@ -886,7 +896,8 @@ unfoldr f seed = -} splitAt : Int -> List a -> ( List a, List a ) splitAt n xs = - ( take n xs, drop n xs ) + splitAtWithReversedInit n [] xs + |> Tuple.mapFirst List.reverse {-| Take elements from the right, while predicate still holds. @@ -1271,3 +1282,30 @@ greedyGroupsOfWithStep size step xs = group :: greedyGroupsOfWithStep size step xs_ else [] + + + +-- Helpers + + +splitAtWithReversedInit : Int -> List a -> List a -> ( List a, List a ) +splitAtWithReversedInit n reversedInit tail = + if n <= 0 then + ( reversedInit, tail ) + else + case tail of + head :: nextTail -> + splitAtWithReversedInit (n - 1) (head :: reversedInit) nextTail + + [] -> + ( reversedInit, tail ) + + +appendUsingReversedInit : List a -> List a -> List a +appendUsingReversedInit reversedInit tail = + case reversedInit of + head :: remainingReversedInit -> + appendUsingReversedInit remainingReversedInit (head :: tail) + + [] -> + tail diff --git a/tests/Tests.elm b/tests/Tests.elm index 521fa78..9ac3cf6 100644 --- a/tests/Tests.elm +++ b/tests/Tests.elm @@ -2,8 +2,9 @@ module Tests exposing (..) import Test exposing (..) import Expect -import Fuzz exposing (list, int, tuple3) +import Fuzz exposing (char, list, int, intRange, tuple3) import List exposing (map, range) +import Random import Tuple exposing (first) import List.Extra exposing (..) @@ -89,6 +90,32 @@ all = \() -> Expect.equal (findIndices (\x -> x % 2 == 0) [ 1, 2, 4 ]) [ 1, 2 ] ] + , describe "insertAt" <| + [ fuzz + (list char |> Fuzz.andThen (\xs -> tuple3 ( intRange 0 (List.length xs), char, Fuzz.constant xs ))) + "0 <= index <= length" + (\( n, x, xs ) -> + Expect.equal + (List.take n xs ++ (x :: List.drop n xs)) + (insertAt n x xs) + ) + , fuzz + (tuple3 ( intRange Random.minInt -1, char, list char )) + "index < 0" + (\( n, x, xs ) -> + Expect.equal + (x :: xs) + (insertAt n x xs) + ) + , fuzz + (list char |> Fuzz.andThen (\xs -> tuple3 ( intRange (List.length xs + 1) Random.maxInt, char, Fuzz.constant xs ))) + "index > length" + (\( n, x, xs ) -> + Expect.equal + (xs ++ [ x ]) + (insertAt n x xs) + ) + ] , describe "intercalate" <| [ test "computes example" <| \() -> @@ -370,7 +397,8 @@ all = \listA listB -> not (List.Extra.isPrefixOf listA listB) || not (List.Extra.isPrefixOf listB listA) - || listA == listB + || listA + == listB |> Expect.true "Expected exactly one to be prefix of the other." , fuzz3 (list int) (list int) (list int) "transitivity" <| \listA listB listC -> @@ -392,7 +420,8 @@ all = \listA listB -> not (List.Extra.isSuffixOf listA listB) || not (List.Extra.isSuffixOf listB listA) - || listA == listB + || listA + == listB |> Expect.true "Expected exactly one to be suffix of the other." , fuzz3 (list int) (list int) (list int) "transitivity" <| \listA listB listC ->