Ruby - Move element of array to given position

Viewed 83

So effectively I'd like to move a given element of an array, by referencing a specific location via a conditional argument passed into the method.

For example if I had an array of

array = [a, b, c, d, f, g]

And created a method along the lines of this with a key value pair as a conditional

def move_element(a, right_of: d)

end

Is this possible with a given array method within Ruby? If so I'm not familiar with it.

Cheers in advance

1 Answers

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']
Related