2015-04-06 5 views
1

Я пытаюсь сортировать массив хэш на основе нескольких ключей и нескольких направлений (ASC и DESC).Как отсортировать Ruby Array of Hashes на основе нескольких ключей и нескольких направлений?

Предположим, массив выглядит следующим образом:

items = [ {field1: '1', field2: 5, field3: 5}, 
      {field1: '1', field2: 1, field3: 3}, 
      {field1: '3', field2: 3, field3: 2}, 
      {field1: '3', field2: 1, field3: 8}, 
      {field1: '7', field2: 5, field3: 6}, 
      {field1: '7', field2: 5, field3: 1} ] 

Я хочу создать multiple_sort (элементы, варианты) метод, который работает, как:

multiple_sort(items, [{field: 'feed1', dir: 'asc'}, {field: 'feed3', dir: 'asc'}]) 

будет генерировать:

 [ {field1: '1', field2: 1, field3: 3}, 
      {field1: '1', field2: 5, field3: 5}, 
      {field1: '3', field2: 3, field3: 2}, 
      {field1: '3', field2: 1, field3: 8}, 
      {field1: '7', field2: 5, field3: 1}, 
      {field1: '7', field2: 5, field3: 6} ] 

И

multiple_sort(items, [{field: 'feed1', dir: 'asc'}, {field: 'feed3', dir: 'desc'}]) 

Выведет:

[ {field1: '1', field2: 5, field3: 5}, 
     {field1: '1', field2: 1, field3: 3} 
     {field1: '3', field2: 1, field3: 8}, 
     {field1: '3', field2: 3, field3: 2}, 
     {field1: '7', field2: 5, field3: 6}, 
     {field1: '7', field2: 5, field3: 1} ] 

Любая помощь будет оценена.

ответ

2

Я позвонил feed1 как field1 и сменил строки на символы эффективности.

def multiple_sort(array, criteria) 
    array.sort do |a, b| 
    cmp = 0 
    criteria.each do |criterion| 
     cmp = a[criterion[:field]] <=> b[criterion[:field]] 
     cmp = -cmp if criterion[:dir] == :desc 
     break if cmp != 0 
    end 
    cmp 
    end 
end 


require 'pp' 

pp multiple_sort(items, [ 
    {field: :field1, dir: :asc}, 
    {field: :field3, dir: :asc} 
]) 
# [{:field1=>"1", :field2=>1, :field3=>3}, 
# {:field1=>"1", :field2=>5, :field3=>5}, 
# {:field1=>"3", :field2=>3, :field3=>2}, 
# {:field1=>"3", :field2=>1, :field3=>8}, 
# {:field1=>"7", :field2=>5, :field3=>1}, 
# {:field1=>"7", :field2=>5, :field3=>6}] 

pp multiple_sort(items, [ 
    {field: :field1, dir: :asc}, 
    {field: :field3, dir: :desc} 
]) 
# [{:field1=>"1", :field2=>5, :field3=>5}, 
# {:field1=>"1", :field2=>1, :field3=>3}, 
# {:field1=>"3", :field2=>1, :field3=>8}, 
# {:field1=>"3", :field2=>3, :field3=>2}, 
# {:field1=>"7", :field2=>5, :field3=>6}, 
# {:field1=>"7", :field2=>5, :field3=>1}] 
0

Вы можете использовать Enumerable#sort_by:

Код

def multiple_sort(items, options) 
    items.sort_by { |h| options.map { |g| 
    ((g[:dir]=='asc') ? 1 : -1) * h[g[:field].to_sym].to_i } } 
end 

Примеры

items = [ {field1: '1', field2: 5, field3: 5}, 
      {field1: '1', field2: 1, field3: 3}, 
      {field1: '3', field2: 3, field3: 2}, 
      {field1: '3', field2: 1, field3: 8}, 
      {field1: '7', field2: 5, field3: 6}, 
      {field1: '7', field2: 5, field3: 1} ] 

options = [{field: 'field1', dir: 'asc'}, {field: 'field3', dir: 'asc'}] 
multiple_sort(items, options) 
    #=> [{:field1=>"1", :field2=>1, :field3=>3}, 
    # {:field1=>"1", :field2=>5, :field3=>5}, 
    # {:field1=>"3", :field2=>3, :field3=>2}, 
    # {:field1=>"3", :field2=>1, :field3=>8}, 
    # {:field1=>"7", :field2=>5, :field3=>1}, 
    # {:field1=>"7", :field2=>5, :field3=>6}] 

options = [{field: 'field1', dir: 'desc'}, {field: 'field3', dir: 'desc'}] 
multiple_sort(items, options) 
    # => [{:field1=>"7", :field2=>5, :field3=>6}, 
    #  {:field1=>"7", :field2=>5, :field3=>1}, 
    #  {:field1=>"3", :field2=>1, :field3=>8}, 
    #  {:field1=>"3", :field2=>3, :field3=>2}, 
    #  {:field1=>"1", :field2=>5, :field3=>5}, 
    #  {:field1=>"1", :field2=>1, :field3=>3}] 

items << {:field1=>"1", :field2=>6, :field3=>5} 
    #=> [{:field1=>"1", :field2=>5, :field3=>5}, 
    # {:field1=>"1", :field2=>1, :field3=>3}, 
    # {:field1=>"3", :field2=>3, :field3=>2}, 
    # {:field1=>"3", :field2=>1, :field3=>8}, 
    # {:field1=>"7", :field2=>5, :field3=>6}, 
    # {:field1=>"7", :field2=>5, :field3=>1}, 
    # {:field1=>"1", :field2=>6, :field3=>5}] 

options = [{field: 'field1', dir: 'asc'}, {field: 'field3', dir: 'desc'}, 
      {field: 'field2', dir: 'desc'}] 
multiple_sort(items, options) 
    #=> [{:field1=>"1", :field2=>6, :field3=>5}, 
    # {:field1=>"1", :field2=>5, :field3=>5}, 
    # {:field1=>"1", :field2=>1, :field3=>3}, 
    # {:field1=>"3", :field2=>1, :field3=>8}, 
    # {:field1=>"3", :field2=>3, :field3=>2}, 
    # {:field1=>"7", :field2=>5, :field3=>6}, 
    # {:field1=>"7", :field2=>5, :field3=>1}] 
Смежные вопросы