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.
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.
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" .
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 .
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.
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).
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With