如何基于多个键和多个方向对Ruby数组进行排序?

时间:2015-04-06 00:52:21

标签: ruby arrays sorting

我试图根据多个键和多个方向(ASC和DESC)对哈希数组进行排序。

假设数组如下:

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(items,options)方法,其工作方式如下:

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 个答案:

答案 0 :(得分: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}]

答案 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}]