Reputation: 23
I am trying to write code that looks for the first two elements in an array that are out of order and swaps them. I wrote this code but am only printing out 3 when I run it. Can someone help me rewrite my code for it to work?
arr = [5, 22, 29, 39, 19, 51, 78, 96, 84]
i = 0
while (i < arr.size - 1 and arr[i] < arr[i + 1])
i = i + 1
end
puts i
arr[i] = arr[i + 1]
arr[i + 1] = arr[i]
Upvotes: 0
Views: 1230
Reputation: 110675
You could write the following:
arr = [5, 22, 29, 39, 19, 51, 78, 96, 84]
i = (0..arr.size-2).find { |i| arr[i] > arr[i+1] }
#=> 3
arr[i], arr[i+1] = arr[i+1], arr[i] unless i.nil?
#=> [19, 39]
arr
#=> [5, 22, 29, 19, 39, 51, 78, 96, 84]
Upvotes: 5
Reputation: 11183
You can use Enumerable#each_cons coupled with Enumerable#each_winth_index for getting the pairs and their indexes(*). Then Enumerable#find the first index of pair in reversed order, Object#then modify the original array inserting the swapped pair:
arr = [1,2,3,5,4]
arr.each_cons(2).with_index.find { |(a, b), i| a > b }
.then { |e, i| arr[i..i+1] = e.reverse if i }
arr
#=> [1, 2, 3, 4, 5]
(*) How it works:
arr.each_cons(2).with_index.to_a
#=> [[[1, 2], 0], [[2, 3], 1], [[3, 5], 2], [[5, 4], 3]]
Note: use Object#yield_self for older Ruby instead of Object#then
Upvotes: 1
Reputation: 21110
The problem with your current code is:
arr[i] = arr[i + 1]
arr[i + 1] = arr[i]
Where you set arr[i]
equal to arr[i + 1]
, then repace the content of arr[i + 1]
with arr[i]
(which is set to arr[i + 1]
). This sets both the elements to the content of arr[i + 1]
. You can use a temporary variable to hold the previous value of arr[i]
.
tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
A cleaner way of doing this is using multiple assignment.
arr[i], arr[i + 1] = arr[i + 1], arr[i]
Which removes the need for the temporary variable.
Taking some inspiration from the answers of Cary Swoveland and iGian. Here is another refactored way of finding the index and swapping the values.
arr = [5, 22, 29, 39, 19, 51, 78, 96, 84]
i = arr.each_cons(2).find_index { |a, b| a > b }
arr[i, 2] = arr[i, 2].reverse if i
arr #=> [5, 22, 29, 19, 39, 51, 78, 96, 84]
Upvotes: 3