Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom sort method in Ruby

I want to specify a custom block method to sort an object array by evaluating two properties. However, after many searches, I didn't find to any example without the <=> operator.

I want to compare a to b:

if a.x less than b.x return -1
if a.x greater than b.x return 1
if a.x equals b.x, then compare by another property , like a.y vs b.y

This is my code and it doesn't work:

ar.sort! do |a,b|
   if a.x < b.y return -1
   elseif a.x > b.x return 1
   else return a.y <=> b.y
end

This block is within a function return is exiting the function and returning -1.

like image 712
alexserver Avatar asked Mar 14 '13 04:03

alexserver


People also ask

How do you sort a method in Ruby?

The Ruby sort method works by comparing elements of a collection using their <=> operator (more about that in a second), using the quicksort algorithm. You can also pass it an optional block if you want to do some custom sorting. The block receives two parameters for you to specify how they should be compared.

How do you sort an array in ascending order in Ruby?

You can use the sort method on an array, hash, or another Enumerable object & you'll get the default sorting behavior (sort based on <=> operator) You can use sort with a block, and two block arguments, to define how one object is different than another (block should return 1, 0, or -1)

How do you sort a hash in Ruby?

To sort a hash in Ruby without using custom algorithms, we will use two sorting methods: the sort and sort_by. Using the built-in methods, we can sort the values in a hash by various parameters.


2 Answers

This will give you ascending order for x then for y:

points.sort_by{ |p| [p.x, p.y] }
like image 177
AJcodez Avatar answered Sep 17 '22 11:09

AJcodez


The best answer is provided by @AJcodez below:

points.sort_by{ |p| [p.x, p.y] }

The "correct" answer I originally provided, while it technically works, is not code I would recommend writing. I recall composing my response to fit the question's use of if/else rather than stopping to think or research whether Ruby had a more expressive, succinct way, which, of course, it does.


With a case statement:

ar.sort do |a, b|
  case
  when a.x < b.x
    -1
  when a.x > b.x
    1
  else
    a.y <=> b.y
  end
end 

With ternary:

ar.sort { |a,b| a.x < b.x ? -1 : (a.x > b.x ? 1 : (a.y <=> b.y)) }
like image 34
rossta Avatar answered Sep 17 '22 11:09

rossta