按值

时间:2015-05-10 23:53:11

标签: ruby-on-rails arrays ruby hash

我有一个包含哈希的数组。我想按created_at值对其进行排序。这是一个数组结构的例子:

请注意,我已经编写了人类可读日期,这些值将是一个时间戳。

[
  {"group1"=>[
                  {:item1=>[{"name" => "Tim", "created_at"=>"4 weeks ago"}]}, 
                  {:item2=>[{"name" => "Jim", "created_at"=>"3 weeks ago"}]}, 
                  {:item3=>[{"name" => "Ted", "created_at"=>"2 weeks ago"}]}, 
             ]
  }, 
  {"group2"=>[
               {:item1=>[{"name" => "Sally", "created_at"=>"1 month ago"}]}, 
               {:item2=>[{"name" => "Willa", "created_at"=>"2 months ago"}]}, 
               {:item3=>[{"name" => "Sammi", "created_at"=>"4 months ago"}]}, 
             ] 
  },
  {"group3"=>[
                 {:item1=>[{"name" => "Jeff", "created_at"=>"1 month ago"}]}, 
                 {:item2=>[{"name" => "Lois", "created_at"=>"1 day ago"}]}, 
                 {:item3=>[{"name" => "Lisa", "created_at"=>"1 week ago"}]}, 
             ] 
  }
]

我想安排上述数据,因此输出首先为group3,因为它包含item,其值{1}}为1天前。接下来是created_at,因为它包含一个值为2周前的项目,group2将是最后一个,因为它最近的日期是一个月前。

如何重新排列此数据?

我在想我可能需要做一些像

这样的事情
group1

按日期对每个组内的数据进行排序,然后按每个组的第一个哈希值对每个组进行排序 - 因为这将是每个组中最新的哈希值,给出完全排序的哈希值,看起来像这样:

 array_of_nested_hashes.each do |a|
      a.sort_by { |k, v| v[:created_at] }
 end

3 个答案:

答案 0 :(得分:2)

这是我的尝试。问题是:

1)对所有内部数组进行排序以获得最大值(意味着最近的数据)      numeric timestamp)到第一个索引。

2)在内部数组中已知位置(索引0)中的最大值,根据第一个值的值对外部数组进行排序     内部数组中的索引。

# Part 1
outer_list.map! do |h|
    Hash[h.map do |k, v|
        v = v.sort_by do |hsh|
            hsh.first[1][0]['created_at'].to_i
        end.reverse!
        [k, v]
    end]
end

# Part 2
sorted = outer_list.sort_by do |h|
    h.first[1][0].first[1][0]['created_at'].to_i
end.reverse!

答案 1 :(得分:1)

修改

以下是对问题的正确解释的答案:

arr = [
  {"g1"=>[{i1: [{"ca"=>-28}]}, {i2: [{"ca"=>-21}]}, {i3: [{"ca"=>-14} ]}]}, 
  {"g2"=>[{i1: [{"ca"=>-30}]}, {i2: [{"ca"=>-60}]}, {i3: [{"ca"=>-120}]}]},
  {"g3"=>[{i1: [{"ca"=>-30}]}, {i2: [{"ca"=>-1}]},  {i3: [{"ca"=>-7}  ]}]}
]

arr.sort_by { |h| h.first.last.map { |g| g["ca"] }.max }.reverse
  #=> [{"g3"=>...}, {"g1"=>...}, {"g2"=>...}]

以下大部分解释也适用于此答案。

<强>潮

这是你可以做到的一种方式,让arr表示你想要排序的哈希数组。

<强>代码

PER_SIZE = { 'day'=>1, 'week'=>7, 'month'=>30 }

arr.sort_by do |g|
  g.first.last.map do |h|
    n, period = h.first.last.first["created_at"].scan(/(\d+) ([a-rt-z]+)/).first
    n.to_i * PER_SIZE[period]
  end.min
end
  #=>[{"group3"=>[{:item2=>[{"name"=>"Lois", "created_at"=>"1 day ago"}]},
  #               {:item3=>[{"name"=>"Lisa", "created_at"=>"1 week ago"}]},
  #               {:item1=>[{"name"=>"Jeff", "created_at"=>"1 month ago"}]}]},
  #   {"group1"=>[{:item3=>[{"name"=>"Ted", "created_at"=>"2 weeks ago"}]},
  #               {:item2=>[{"name"=>"Jim", "created_at"=>"3 weeks ago"}]},
  #               {:item1=>[{"name"=>"Tim", "created_at"=>"4 weeks ago"}]}]},
  #   {"group2"=>[{:item1=>[{"name"=>"Sally", "created_at"=>"1 month ago"}]},
  #               {:item2=>[{"name"=>"Willa", "created_at"=>"2 months ago"}]},
  #               {:item3=>[{"name"=>"Sammi", "created_at"=>"4 months ago"}]}]}]

<强>解释

可以通过将每个日期字符串转换为天数来完成排序。我们首先将一个变量赋给枚举器arr.sort_by。然后我们可以使用Enumerator#next来获取枚举数的每个值,然后我们将其传递给块。

enum = arr.sort_by
  #=> #<Enumerator:
  #     [{"group1"=>[{:item1=>
  #       [{"name"=>"Tim", "created_at"=>"4 weeks ago"}]},...
  #   :sort_by>

现在将枚举数的第一个值分配给块变量:

g = enum.next
  #=> {"group1"=>[{:item1=>[{"name"=>"Tim", "created_at"=>"4 weeks ago"}]},
  #               {:item2=>[{"name"=>"Jim", "created_at"=>"3 weeks ago"}]},
  #               {:item3=>[{"name"=>"Ted", "created_at"=>"2 weeks ago"}]}]} 
arr1 = g.first.last
  #=> ["group1", [{:item1=>[{"name"=>"Tim", "created_at"=>"4 weeks ago"}]},
  #               {:item2=>[{"name"=>"Jim", "created_at"=>"3 weeks ago"}]},
  #               {:item3=>[{"name"=>"Ted", "created_at"=>"2 weeks ago"}]}]]
arr1
  #=> [{:item1=>[{"name"=>"Tim", "created_at"=>"4 weeks ago"}]},
  #    {:item2=>[{"name"=>"Jim", "created_at"=>"3 weeks ago"}]},
  #    {:item3=>[{"name"=>"Ted", "created_at"=>"2 weeks ago"}]}] 

maparr的第一个元素传递给块,并将其分配给块变量:

h = {:item1=>[{"name"=>"Tim", "created_at"=>"4 weeks ago"}]}

arr2 = h.first.last
  #=> [{"name"=>"Tim", "created_at"=>"4 weeks ago"}] 

s = arr2.first["created_at"]
  #=> "4 weeks ago" 
arr3 = s.scan(/(\d+) ([a-rt-z]+)/)
  #=> [["4", "week"]] 
n, period = arr3.first
  #=> ["4", "week"] 
n      #=> "4" 
period #=> "week" 
n.to_i * PER_SIZE[period]
  #=> 4 * PER_SIZE['week']
  #=> 4 * 7 => 28

同样,arr1的第二和第三个元素分别映射到2114(天)。然后我们计算:

[28, 21, 14].min
  #=> 14

sort_by用于arr[0]的值。同样,sort_by的{​​{1}}值为:

arr[1]

[30, 60, 120].min #=> 30 是:

arr[2]

因此,[30, 1, 7].min #=> 1 分类为:

arr

答案 2 :(得分:0)

知道它们实际上是时间戳之后..

这是我的回答

obj = {that huge array} 
sorted_obj = obj.sort_by do |groups|
  groups.values.map do |items|
    items.map do |item|
      item.values.flatten.first['created_at']
    end.max
  end
end