Сортировка массива хэшей в ruby - PullRequest
1 голос
/ 21 марта 2012

У меня есть массив хэшей, которые выглядят так:

ward = {id: id, name: record["Externalization"], mnemonic: record["Mnemonic"],
   seqno: record["SeqNo"]}

Все поля являются строками.

Теперь я хочу отсортировать их сначала по seqno, а затем по имени. seqno может быть ноль (если seqno ноль, то этот приход должен идти после тех, кто имеет seqno).

Что у меня пока есть:

wardList.sort! do |a,b| 
  return (a[:name] <=> b[:name]) if (a[:seqno].nil? && b[:seqno].nil?) 
  return -1 if a[:seqno].nil?
  return 1 if b[:seqno].nil?
  (a[:seqno] <=> b[:seqno]).nonzero? ||
    (a[:name] <=> b[:name])
end

Но это дает мне ошибку: не может преобразовать символ в целое число

Ответы [ 3 ]

2 голосов
/ 21 марта 2012

Во-первых, нормализуйте ваши данные , вы не можете работать с целыми числами в виде строк:

wardList = wardList.map { |x| x.merge({:id    => x[:id].to_i, 
                                       :seqno => x[:seqno].try(:to_i) }) }

Тогда вы можете использовать sort_by, который поддерживает лексикографическую сортировку:

wardList.sort_by! { |x| [x[:seqno] || Float::INFINITY, x[:name]] }

Пример:

irb(main):034:0> a = [{:seqno=>5, :name=>"xsd"}, 
                      {:seqno=>nil, :name=>"foo"}, 
                      {:seqno=>nil, :name=>"bar"}, 
                      {:seqno=>1, :name=>"meh"}]
irb(main):033:0> a.sort_by { |x| [x[:seqno] || Float::INFINITY, x[:name]] }
=> [{:seqno=>1, :name=>"meh"},
    {:seqno=>5, :name=>"xsd"},
    {:seqno=>nil, :name=>"bar"},
    {:seqno=>nil, :name=>"foo"}]
1 голос
/ 21 марта 2012

Это должно работать:

sorted = wardList.sort_by{|a| [a[:seqno] ? 0 : 1, a[:seqno], a[:name]] }

или для некоторых рубинов (например, 1.8.7):

sorted = wardList.sort_by{|a| [a[:seqno] ? 0 : 1, a[:seqno] || 0, a[:name]] }
0 голосов
/ 21 марта 2012

Я не думаю, что вы должны использовать return здесь, это заставляет блок возвращаться к итератору, итератор возвращается к включающему методу, а закрывающий метод возвращается к своему вызывающему.Вместо этого используйте next, который заставляет блок возвращаться к итератору (в данном случае sort!) и делает что-то вроде:

wardList.sort! do |x,y|
  next  1 if x[:seqno].nil?
  next -1 if y[:seqno].nil?
  comp = x[:seqno] <=> y[:seqno]
  comp.zero? ? x[:name] <=> y[:name] : comp
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...