saramarah
saramarah

Reputation: 23

Swap first two elements in array that aren't sorted

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

Answers (3)

Cary Swoveland
Cary Swoveland

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

iGian
iGian

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

3limin4t0r
3limin4t0r

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

Related Questions