2

I want to move the element at index 2 to the start of the array [1, 2, 3, 4], the resulting array should look like [3, 1, 2, 4].

My solution was to do the following

[3] + ([1, 2, 3, 4] - [3])

Is there a better way to do this?

5
  • its not rotation, relevant order is changed of values that's not the case of rotation. If you rotate this array by 2 index then you will get - [3,4,1,2]. Commented Jan 10, 2023 at 5:08
  • It is not rotation.. It's partial rotation, the title says exactly that. Commented Jan 10, 2023 at 5:21
  • 1
    [1, 2, 3, 4].values_at(2, 0..1, 3) would work (and could be further generalized) Commented Jan 10, 2023 at 9:14
  • @CarySwoveland If it's not partial rotation, what else should I call it? To me it is similar to [1,2,3,4].rotate(-1) which rotates the entire array clockwise by 1. Commented Jan 11, 2023 at 6:55
  • I think the generalization @Stefan is referring to would be i = 2; [1, 2, 3, 4].values_at(i, 0...i, i+1..) #=> [3, 1, 2, 4]. This works for all i, 0 <= i <= 3. Commented Jan 13, 2023 at 2:13

3 Answers 3

4

A method that takes the first n elements from an array and rotates them by one, then adds back the remaining elements.

def rotate_first_n_right(arr, n)
  arr[0...n].rotate(-1) + arr[n..-1]
end

rotate_first_n_right([1,2,3,4], 3)
# => [3, 1, 2, 4]

This does fail if we try to use it on an array that is too short, as the arr[n..-1] slice will yield nil which will cause an error when we try to add it to the first array.

We can fix this by expanding both slices into a list.

def rotate_first_n_right(arr, n)
  [*arr[0...n].rotate(-1), *arr[n..-1]]
end

To see why this works, a very simple example:

[*[1, 2, 3], *nil]
# => [1, 2, 3]

A problem with your example is what happens if 3 occurs in the array more than once. E.g.

[1,2,3,3,3,4] - [3]
# => [1, 2, 4]
Sign up to request clarification or add additional context in comments.

2 Comments

ar[0...3] = ar[0...3].rotate(-1) is also an option.
Alternatively cap n at arr.length to avoid nil. Or maybe even raise an exception. (what does it even mean to rotate the first 4 items of a 3-element array?)
3

Not sure what you mean about "rotation" as this is not exactly a rotation but you could go with

def move_element_to_front(arr, idx)
  # ruby >= 2.6 arr.dup.then {|a| a.unshift(a.delete_at(idx)) } 
  arr = arr.dup
  arr.unshift(arr.delete_at(idx))
end

This will move the element at idx to the first position in the returned Array

2 Comments

"this is not exactly a rotation" – you could see this as rotating the arr[0..idx] subarray (to the left). This is what the OP meant by "partial rotation" as you're not rotating the entire array.
@Stefan I could see that and would be more inclined to agree if this was a repeated movement e.g. [3,1,2,4], [2,3,1,4], etc. then terminologically speaking I am not sure I could come up with a better explanation of this pattern than partial rotation.
2
def move_element_to_front(arr, idx)
  [arr[idx]].concat(arr[0,idx], arr[idx+1..])
end
arr = [:dog, :cat, :pig, :hen]
move_element_to_front(arr, 2)
  #=> [:pig, :dog, :cat, :hen]
move_element_to_front(arr, 0)
  #=> [:dog, :cat, :pig, :hen]
move_element_to_front(arr, 3)
  #=> [:hen, :dog, :cat, :pig]

The operative line of the method could alternatively be expressed

[arr[idx], *arr[0,idx], *arr[idx+1..]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.