Подтвердить что ты не робот

Сортировка массива массивов в Ruby

У меня есть массив массивов, например:

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

Я хотел бы отсортировать все device_array на 4-м элементе.

Я пробовал

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

Я также пробовал:

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

Оба метода не сработали.

Я использовал это как ссылку: http://ariejan.net/2007/01/28/ruby-sort-an-array-of-objects-by-an-attribute/

Я предполагаю, что мне не хватает чего-то рубинового, что делает это очень легким.

4b9b3361

Ответ 1

Вы не можете использовать <=> с nil.

Ваш код должен выглядеть примерно так:

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

Это приведет к тому, что подмассивы, не имеющие элемента индекса 4 в начале результата. Чтобы сделать это наоборот, замените -1 на 1.

Вы также можете использовать sort_by вместо sort. Я думаю, что это было введено в Ruby 1.8.7 (так что это может не сработать, если вы используете более старую версию). Это выглядит примерно так:

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

Это будет обрабатывать субмассивы без 4-го элемента, как если бы это было 0. Измените эту константу в соответствии с вами.

EDIT:

После того, как вы отредактировали вход, теперь ясно, что вы были очень близки к правильному ответу. Ваш код должен быть:

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

Или просто (при условии, что Ruby 1.8.7 или больше):

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

В обоих случаях переменные a и b будут содержать элементы исходного массива, поэтому вы можете напрямую обращаться к элементу в любой позиции (и вам не нужно что-то вроде a[][4], которое неверный синтаксис Ruby).

Ответ 2

4-й элемент фактически находится в индексе 3, что означает, что вы сделали бы это следующим образом:

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

Если вы действительно хотите отсортировать элементы в индексе 4 (который не существует для первого элемента all_devices), вам нужно сначала добавить сравнение с NilClass:

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

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

Это сортирует nil до конца. Измените возвращаемое значение <=> на -1, чтобы отсортировать их спереди.

Ответ 3

Я знаю, что на вопрос был дан ответ, и я не буду сейчас обращаться к нему, но..

Вы уверены, что массив будет лучше всего подходит для этих данных? Я говорю об этих элементах данных: [ "name1", "type1", [ "A", "N", "N" ], [ "Attribute", "device_attribute" ], 9]

Похоже на Struct, или что-то может быть более подходящим и управляемым для этого, и тогда у вас может быть массив Structs. Просто идея.

Ответ 4

sort_by

Вместо использования оператора космического корабля (<=>) попробуйте sort_by

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

Хотя, если вы знаете, что четвертый элемент является последним, вы также можете использовать el.last в блоке.

Документы Ruby: Enumerable # sort_by