Ruby通过其键对多维数组进行排序

时间:2018-07-06 11:52:12

标签: ruby sinatra

我想对数组进行排序,以升序或降序排序。 我的数组包含哈希键,我要排序的值是float,integer和string(名称)。名称可以是字母或字母数字。我想创建一个可以处理所有排序的方法。它将采用数组,列名和排序顺序,并返回已排序的其余数组。 以下是JSON输出。我的数组包含哈希键。

[
  {
    "sid": "101",
    "snumber": "798798",
    "name": "Anita 1",
    "time": 1800,
    "count": 32,
    "hour": "",
    "avg": 1
  },
  {
    "sid": "160",
    "snumber": "6546546",
    "name": "Anita 22",
    "time": 1300,
    "count": 30,
    "hour": "1",
    "avg": 1
  },
  {
    "sid": "120",
    "snumber": "6546546",
    "name": "Anita",
    "time": 2300,
    "count": 10,
    "hour": "2",
    "avg": 2
  }
]

我尝试了很多事情,但是做错了什么。这是我的方法:

def self.sort_by_alphabets(arr, sortColumnName, sortOrder) # sortOrder a: ASC,d: DESC
    column = sortColumnName.to_sym
    return arr.sort_by { |h| 
        if sortColumnName == 'sid' || sortColumnName = 'snumber' || sortColumnName =='hour'
            a = h[column].to_i
        else
            if h[column].is_a? String
                a = h[column].to_s
                type ='s'
            elsif h[column].is_a? Float
                a = h[column].to_f
                type ='f'
            else
                a = h[column].to_i
                type ='i'
            end

       if sortOrder == 'a'
        a.downcase
       else
        a.upcase
       end

    }
  end

有人可以帮我吗?

期望的输出是排序数组。假设如果我想使用sid来对数组进行升序排序,则结果数组将按上述顺序按sid进行排序,其他键也是如此。但是,一次只能将数组按任何一个键排序。

3 个答案:

答案 0 :(得分:3)

代码

def sort_by_value(arr, key, ascending = true)
  arr.sort_by do |h|
    v = h[key]
    raise TypeError, "#{v}.class => #{v.class} invalid" unless
      (v.kind_of?(Numeric) && !v.is_a?(Complex)) || v.is_a?(String)
    Float(v) rescue v.downcase
  end.tap { |a| a.reverse! if ascending == false }
end

请参见Enumerable#sort_byObject#kind_of?Kernel#Float

我假设当值是代表数字值(不是复数)的字符串时,将对关联的数字进行排序。 Float(v)尝试将字符串v转换为浮点数。如果成功,则返回float;否则,它将引发被抢救的异常(行内),从而导致返回v.downcase

示例

arr = [
  { "name"=>"Anita 1",  "time"=>18, "wt"=>2.31,  "inbr"=>  "79", "fnbr"=>"-2.31"    },
  { "name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=> "654", "fnbr"=>"12.4"     },
  { "name"=>"bubba",    "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2" }
]

sort_by_value(arr, "name")
  #=> [{"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79","fnbr"=>"-2.31"}
  #    {"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654","fnbr"=>"12.4"},
  #    {"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654","fnbr"=>"-1284e-2"}]
sort_by_value(arr, "name", false)
  #=> [{"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654",  "fnbr"=>"-1284e-2"},
  #    {"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654",  "fnbr"=>"12.4"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79",  "fnbr"=>"-2.31"}]

sort_by_value(arr, "time")
  #=> [{"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  #    {"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"}]
sort_by_value(arr, "time", false)
  #=> [{"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  #    {"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"}]

sort_by_value(arr, "wt")
  #=> [{"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  #    {"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"}]
sort_by_value(arr, "wt", false)
  #=> [{"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  #    {"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"}]

sort_by_value(arr, "inbr")
  #=> [{"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  #    {"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"}]
sort_by_value(arr, "inbr", false)
  #=> [{"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"},
  # {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  # {"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"}]

sort_by_value(arr, "fnbr")
  #=> [{"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  #    {"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"}]
sort_by_value(arr, "fnbr", false)
  #=> [{"name"=>"Anita 22", "time"=>13, "wt"=>-12.4, "inbr"=>"654", "fnbr"=>"12.4"},
  #    {"name"=>"Anita 1", "time"=>18, "wt"=>2.31, "inbr"=>"79", "fnbr"=>"-2.31"},
  #    {"name"=>"bubba", "time"=>23, "wt"=>12.84, "inbr"=>"-654", "fnbr"=>"-1284e-2"}]

答案 1 :(得分:0)

输入

ary = [{
        "sid" => "101",
        "snumber" => "798798",
        "name" => "Ben",
        "time" => 1800,
        "count" => 32,
        "hour" => "",
        "avg" => 1
      },
      {
        "sid" => "160",
        "snumber" => "6546546",
        "name" => "anita",
        "time" => 1300,
        "count" => 30,
        "hour" => "1",
        "avg" => 1
      },
      {
        "sid" => "120",
        "snumber" => "6546546",
        "name" => "Jake",
        "time" => 2300,
        "count" => 10,
        "hour" => "2",
        "avg" => 2
      }]

解决方案

我假设您想按任何列进行排序,无论其值是数字还是字符串。我不知道您为什么尝试使用downcase。如果那有特殊含义,请提及。我将更新答案。

def sort_by_key(ary, column, order)
  # I am working on hashes with stringified keys, so not doing `to_sym` on `column`. You can uncomment below line if your hashes has symbol keys.
  # column = column.to_sym

  order = order.to_sym
  raise 'Unknown sort order' unless %i[asc desc].include?(order)

  ary.sort do |x, y|
    order == :asc ?
      x[column] <=> y[column] :
      y[column] <=> x[column]
  end 
end

sort_by_key(ary, 'sid', :desc)
 => [{"sid"=>"160", "snumber"=>"6546546", "name"=>"anita", "time"=>1300, "count"=>30, "hour"=>"1", "avg"=>1},
     {"sid"=>"120", "snumber"=>"6546546", "name"=>"Jake", "time"=>2300, "count"=>10, "hour"=>"2", "avg"=>2},
     {"sid"=>"101", "snumber"=>"798798", "name"=>"Ben", "time"=>1800, "count"=>32, "hour"=>"", "avg"=>1}]

sort_by_key(ary, 'name', :asc)
 => [{"sid"=>"101", "snumber"=>"798798", "name"=>"Ben", "time"=>1800, "count"=>32, "hour"=>"", "avg"=>1},
     {"sid"=>"120", "snumber"=>"6546546", "name"=>"Jake", "time"=>2300, "count"=>10, "hour"=>"2", "avg"=>2},
     {"sid"=>"160", "snumber"=>"6546546", "name"=>"anita", "time"=>1300, "count"=>30, "hour"=>"1", "avg"=>1}]

查看“ anita”如何排在最后,因为默认情况下所有大写字母排在小写字母之前。

如果要对名称进行排序(不区分大小写),请如下修改方法:

def sort_by_key(ary, column, order)
  ...
  ary.sort do |x, y|
    val_x, val_y = [x, y].map { |hash| hash[column] }
    val_x, val_y = [val_x, val_y].map(&:downcase) if [val_x, val_y].all? { |v| v.respond_to?(:downcase) }
    order == :asc ?
      val_x <=> val_y :
      val_y <=> val_x
  end
end

sort_by_key(ary, 'name', :asc)
 => [{"sid"=>"160", "snumber"=>"6546546", "name"=>"anita", "time"=>1300, "count"=>30, "hour"=>"1", "avg"=>1},
     {"sid"=>"101", "snumber"=>"798798", "name"=>"Ben", "time"=>1800, "count"=>32, "hour"=>"", "avg"=>1},
     {"sid"=>"120", "snumber"=>"6546546", "name"=>"Jake", "time"=>2300, "count"=>10, "hour"=>"2", "avg"=>2}]

注意:您将键"hour"的值存储为字符串。因此,排序将像其他任何字符串一样对它们进行处理"hour"值“ 12”将先于值“ 2”。要解决此问题,您可以使用String#to_i"hour"的字符串值转换为整数。

答案 2 :(得分:0)

如果要修补数组类,可以执行以下操作,例如:

module ArrayPatch
  def sort_by_key(key, order = :asc)
    sorted = sort_by { |hash| hash[key] }
    sorted.reverse! if order == :desc
    sorted
  end
end

Array.include ArrayPatch

默认订单为:asc,可以跳过order参数:

array.sort_by_key(:name)
# => [{:sid=>"120", :snumber=>"6546546", :name=>"Anita", :time=>2300, :count=>10, :hour=>"2", :avg=>2}, {:sid=>"101", :snumber=>"798798", :name=>"Anita 1", :time=>1800, :count=>32, :hour=>"", :avg=>1}, {:sid=>"160", :snumber=>"6546546", :name=>"Anita 22", :time=>1300, :count=>30, :hour=>"1", :avg=>1}]

或添加:desc以颠倒顺序:

array.sort_by_key(:name, :desc)
#=> [{:sid=>"160", :snumber=>"6546546", :name=>"Anita 22", :time=>1300, :count=>30, :hour=>"1", :avg=>1}, {:sid=>"101", :snumber=>"798798", :name=>"Anita 1", :time=>1800, :count=>32, :hour=>"", :avg=>1}, {:sid=>"120", :snumber=>"6546546", :name=>"Anita", :time=>2300, :count=>10, :hour=>"2", :avg=>2}]

我省略了对参数的任何错误处理。

编辑:这可能会失败,并且字符串代表数字:"1", "12", "2"是String类对象的有序序列,但是期望值为"1", "2", "12"。万一,最好的选择是https://stackoverflow.com/a/51215213/5239030