【问题标题】:Sort a hash by value inside other hash - Ruby on Rails在其他散列中按值对散列进行排序 - Ruby on Rails
【发布时间】:2014-07-03 00:59:31
【问题描述】:

我有一个包含另一个哈希的哈希,我需要按如下方式排序:

data = {
    "user": {
        "name": "John",
        "age": "36",
    },
    "company": "Terminal",
    "country": "Canada",
} 
{
    "user": {
        "name": "Mary",
        "age": "32",
    },
    "company": "Brasco",
    "country": "Italy",
}

使用这种方式我可以毫无问题地排序:

data.sort_by { |a| [a[:company], a[:country]] }

但如果“公司”和“国家”具有相同的值,我需要按第三个选项“名称”进行排序。

情况是我需要在最后使用'reverse'功能(我贴的例子不是真实情况,真实的太大了...lol)。

所以结果也是把名字倒过来排序了。

data.sort_by { |a| [a['company'], a['country'], a['user']['name']] }.reverse

我需要 DESC 中的“公司”和“国家/地区”排序以及 ASC 中的 user.name 排序。

【问题讨论】:

  • 您能提供一个有效的输入吗?

标签: ruby-on-rails ruby sorting hash


【解决方案1】:
data.sort_by { |a| [a['company'], a['country'], a['user']['name']] }

sort_by 接收到一个数组时,它会在前一个元素相同时比较每个元素。

如果您想对company ASC, country ASC, name ASC 进行排序,然后轻松地将其反转为company DESC, country DESC, name ASC,您可以这样做:

sorted = data.group_by do |x| 
  [x['company'], x['country']] 
end.each do |k, v| 
  v.sort_by! { |x| x[:user][:name] } 
end.sort_by(&:first).map(&:last)

这将创建一个数组数组,每个内部数组包含公司/国家对中的所有用户,按名称排序。

现在获取您应该执行的 ASC 选项:

sorted.flatten

反之(用户仍然是 ASC),您需要:

sorted.reverse.flatten

【讨论】:

  • @SérgioToledo 请告诉我这是如何失败的,以便我检查差异。它应该可以正常工作。
  • 你是对的@UriAgassi,但我需要更多的东西。我编辑了问题并提供了更多信息。
  • 伟大的@UriAgassi,你解决了这个问题!并感谢“.flatten”方法,我也会在程序的其他部分使用它;)
【解决方案2】:

这个怎么样

data = [
{
 "user" => {
    "name" => 'John',
    "age" => "36",
  },
  "company" => "Terminal"
  "country" => "Canada"
},
{
"user" => {
    "name" => 'Mary',
    "age" => "32",
  },
  "company" => "Brasco",
  "country" => "Italy"
},
{
"user" => {
    "name" => 'Andre',
    "age" => "32",
  },
  "company" => "Brasco",
  "country" => "Italy"
}]


data.sort do |a,b| 
  sort_direction = [a['company'],a['country']] <=> [b['company'],b['country']]
  b['user']['name'] <=> a['user']['name'] if sort_direction == 0
end
#=>=> [{"user"=>{"name"=>"Mary", "age"=>"32"}, "company"=>"Brasco", "country"=>"Italy"}{"user"=>{"name"=>"Andre", "age"=>"32"},"company"=>"Brasco", "country"=>"Italy"},{"user"=>{"name"=>"John", "age"=>"36"}, "company"=>"Terminal","country"=>"Canada"}]

【讨论】:

  • case [a1, a2] &lt;=&gt; [b1, b2]; when -1; -1; when 1; 1; when 0; b3 &lt;=&gt; a3; end 如果你想走这条路
  • @VictorMoroz 你在评论里说什么?这可以正常工作
  • 你有两个你并不真正需要的额外比较,好吧,我承认case 也是一个比较,但看起来更干净
  • @VictorMoroz 我明白你在说什么,因为它最初是有条件地比较它们,然后如果条件为假则重新比较。感谢您的说明和效率,我明白了这一点,尽管我不同意可读性部分,因为我认为案例陈述读起来很糟糕。
  • @VictorMoroz 编辑限制比较
【解决方案3】:

如果你经常这样做,可能的方式:

class Reverser
  attr_reader :v

  def initialize(v)
    @v = v
  end

  def self.[](v)
    new(v)
  end

  def <=>(other)
    other.v <=> @v
  end
end

# Order by company DESC, country DESC, user.name ASC
data.sort_by { |a| [Reverser[a['company']], Reverser[a['country']], a['user']['name']] }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-26
    • 2014-05-07
    • 2014-01-08
    • 2012-10-09
    • 2010-11-02
    • 2023-03-25
    • 2014-05-19
    • 1970-01-01
    相关资源
    最近更新 更多