Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting an array of arrays in Ruby

Tags:

I have an array of arrays like so:

irb(main):028:0> device_array => [["name1", "type1", ["A", "N", "N"], ["Attribute", "device_attribute"], 9], ["name2","type2", ["A", "N", "N"], ["Attribute", "device_attribute"], 7]] 

I would like to sort the entire device_array on the 4th element.

I've tried

AllDevicesController.all_devices.sort do | a,b |   for i in 0..(AllDevicesController.all_devices.length - 1) do     a[i][4] <=> b[i][4]   end end 

I've also tried:

AllDevicesController.all_devices.sort do | a,b |   a[][4] <=> b[][4] end 

Both methods have not worked.

I was using this as a reference: http://ariejan.net/2007/01/28/ruby-sort-an-array-of-objects-by-an-attribute/

I imagine I'm missing something rubyish that makes this really easy.

like image 590
Tyler K Avatar asked Jul 28 '09 14:07

Tyler K


People also ask

How can you sort an array 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 I group an array in Ruby?

The group by creates a hash from the capitalize d version of an album name to an array containing all the strings in list that match it (e.g. "Enter sandman" => ["Enter Sandman", "Enter sandman"] ). The map then replaces each array with its length, so you get e.g. ["Enter sandman", 2] for "Enter sandman" .

What is .first in Ruby?

first is a property of an array in Ruby that returns the first element of an array. If the array is empty, it returns nil. array. first accesses the first element of the array, i.e., the element at index 0 .

Can you split an array Ruby?

split is a String class method in Ruby which is used to split the given string into an array of substrings based on a pattern specified. Here the pattern can be a Regular Expression or a string. If pattern is a Regular Expression or a string, str is divided where the pattern matches.


2 Answers

You can't use <=> with nil.

Your code should be something like this:

AllDevicesController.all_devices.sort do |a, b|   a[4].nil? ? -1 : b[4].nil? ? 1 : a[4] <=> b[4] end 

This will put the sub-arrays that have no element of index 4 at the beginning of the result. To do it the other way around, swap -1 with 1.

You could also use sort_by instead of sort. I think this has been introduced in Ruby 1.8.7 (so it might not work if you are using an older version). It goes something like:

AllDevicesController.all_devices.sort_by { |e| e.nil? ? 0 : e[4] } 

This will treat sub-arrays with no 4th element as if it was 0. Change this constant to suit you.

EDIT:

After you adjusted the input, it is now clear you were very close to the right answer. Your code should have been:

AllDevicesController.all_devices.sort do |a, b|   a[4] <=> b[4] end 

Or simple (assuming Ruby 1.8.7 or more):

AllDevicesController.all_devices.sort_by { |e| e[4] } 

In both cases, the variables a and b will contain elements of the original array, this is why you can directly access an element in any position (and you don't need something like a[][4], which is incorrect Ruby syntax).

like image 162
Sinan Taifour Avatar answered Oct 19 '22 23:10

Sinan Taifour


sort_by

Instead of using spaceship operator (<=>) give a try to sort_by

device_array.sort_by { |el| el[4] } 

Though if you know that the forth element is the last one, you can use el.last too in the block.

Ruby docs: Enumerable#sort_by

like image 23
Mark Avatar answered Oct 20 '22 01:10

Mark