We are given:
arr = ['a', 'b', 'c', 'd', 'f', 'g']
Initially I assume you wish to modify (mutate) arr (rather than create a new array and leave arr undisturbed). Later I construct a method that does not mutate arr.
Let's first constuct a method that takes as arguments the index of the element to be moved, the index of the element it is to follow and, of course, the array:
def move_position(arr, n1, right_of:)
arr.insert(right_of, arr.delete_at(n1))
end
Try it.
move_position(arr, 1, right_of: 3)
#=> ["a", "c", "d", "b", "f", "g"]
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_position(arr, 0, right_of: 3)
#=> ["b", "c", "d", "a", "f", "g"]
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_position(arr, 0, right_of: 5)
#=> ["b", "c", "d", "f", "g", "a"]
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_position(arr, 0, right_of: 0)
#=> ["a", "b", "c", "d", "f", "g"]
See Array#index. Note that arr.index(i,o) inserts o before the element at index i, but since
a = arr.delete_at(n1)
is executed before
arr.insert(right_of, a)
o is inserted after the element originally at index i.
Note that right_of: in
def move_position(arr, n1, right_of:)
specifies that the value of :right_of is a required variable (no default value, as when right_of: 3 is used). Named parameters (or arguments) were introduced in Ruby v2.0. The syntax for making a named parameter required was added in Ruby v2.1.
Now create a method that replaces the two indices with the elements found at those indices. This only works, of course, when the two elements involved are unique in the array.
def move_element(arr, e1, right_of:)
move_position(arr, arr.index(e1), right_of: arr.index(right_of))
end
This this method.
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_element(arr, 'b', right_of: 'd')
#=> ["a", "c", "d", "b", "f", "g"]
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_element(arr, 'a', right_of: 'd')
#=> ["b", "c", "d", "a", "f", "g"]
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_element(arr, 'a', right_of: 'g')
#=> ["b", "c", "d", "f", "g", "a"]
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_element(arr, 'a', right_of: 'a')
#=> ["a", "b", "c", "d", "f", "g"]
If you do not wish to mutate arr you can write the following:
def move_position(arr, n1, right_of:)
arr.each_index.map do |i|
case i
when 0..n1-1, (right_of+1)..arr.size-1
arr[i]
when n1..right_of-1
arr[i+1]
when right_of
arr[n1]
end
end
end
arr = ['a', 'b', 'c', 'd', 'f', 'g']
move_position(arr, 1, right_of: 3)
#=> ["a", "c", "d", "b", "f", "g"]
move_position(arr, 0, right_of: 3)
#=> ["b", "c", "d", "a", "f", "g"]
move_position(arr, 0, right_of: 5)
#=> ["b", "c", "d", "f", "g", "a"]
move_position(arr, 0, right_of: 0)
#=> ["a", "b", "c", "d", "f", "g"]
Confirm arr has not been mutated:
arr
#=> ["a", "b", "c", "d", "f", "g"]
move_element is unchanged:
move_element(arr, 'b', right_of: 'd')
#=> ["a", "c", "d", "b", "f", "g"]
move_element(arr, 'a', right_of: 'd')
#=> ["b", "c", "d", "a", "f", "g"]
move_element(arr, 'a', right_of: 'g')
#=> ["b", "c", "d", "f", "g", "a"]
move_element(arr, 'a', right_of: 'a')
#=> ['a', 'b', 'c', 'd', 'f', 'g']
arr
#=> ['a', 'b', 'c', 'd', 'f', 'g']