Uğurcan Şahin
Uğurcan Şahin

Reputation: 43

How to move 1 element of a List to right or left in Haskell?

Hi I have been looking for an answer but could not find one. Lets say that we have a list like [1,10,4,5,3] how can I shift 5 to left so that this list becomes [1,10,5,4,3].

I tried to swapElementsAt by finding the index of that element but it looks very insufficient.

Upvotes: 2

Views: 1122

Answers (2)

0xd34df00d
0xd34df00d

Reputation: 1505

Consider how would you write this function if you were to traverse the input list from left to right looking at a very local vicinity of the beginning of the list (since that's what you can easily pattern-match on).

The most straightforward way would be to pattern-match on the first two elements, and check if the second element matches your pattern. If so, just build a new list by swapping these elements and appending the remainder of the list, otherwise, go recursively over the rest.

In code:

swapElem :: Eq a => a -> [a] -> [a]
swapElem e (x:y:xs) | y == e = y : x : xs
swapElem e (x:xs) = x : swapElem e xs
swapElem _ [] = []

The first pattern only matches when there are at least two elements in the list, and the second element is equal to the desired one. If there are less elements or the second element is not the right one, it will fall through to the second pattern, that matches arbitrary non-empty list and calls swapElem on the remainder of the list. The third pattern is there to provide the base recursion case of an empty input list.

Note this code only changes the first occurrence of the target element:

Prelude> swapElem 5 [1, 10, 4, 5, 3]
[1,10,5,4,3]
Prelude> swapElem 5 [1, 10, 5, 4, 5, 3]
[1,5,10,4,5,3]

How would you change it so that it left-shifts all 5s?

Also, the answer depends on what exactly is your input. The answer by @Scarabyte considers the case where you're given the position of the target element, while this approach instead considers the element that you want to shift left.

Upvotes: 0

Scarabyte
Scarabyte

Reputation: 303

swapElementsAt :: Int -> [a] -> [a]                                             
swapElementsAt n list = let (beg, a:b:rest) = splitAt (n-1) list in beg ++ b:a:rest

It works like

λ> swapElementsAt 3 [1,10,4,5,3]
[1,10,5,4,3]

Upvotes: 1

Related Questions