Сортировка массива массивов в 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/
Я предполагаю, что мне не хватает чего-то рубинового, что делает это очень легким.
Ответы
Ответ 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