tags:

views:

681

answers:

3

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.

+4  A: 

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).

Sinan Taifour
I, of course, left out the 4th element of the 0th element of the device_array. There shouldn't be any nil objects.
Tyler K
In that case your only problem is using `a[][4]` instead of `a[4]`. `a[][4]` is not valid Ruby syntax.
Sinan Taifour
A: 

The 4th element is actually at index 3, which means you would do it like this:

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

If you really want to sort the elements at index 4 (which doesn't exist for the first element of all_devices), then you need to add comparison to the NilClass first:

class NilClass
  def <=> (other)
    1
  end
end

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

This will sort nil to the end. Change the return value of <=> to -1 to sort them to the front.

Pesto
This method can end up making catching bugs a bit harder; as it would allow comparison with `nil` everywhere in code. It should be used wisely.
Sinan Taifour
+2  A: 

I know the question has been answered, and I'm not going to address it now, but..

Are you sure an array would be the best fit for that data? I'm talking about these data elements: ["name1", "type1", ["A", "N", "N"], ["Attribute", "device_attribute"], 9]

Seems like a Struct or something might be more appropriate and manageable for this, and then you can have an array of Structs. Just an idea.

ehsanul