簡體   English   中英

按值對哈希數組進行排序

[英]Sort array of hashes by a value

我有一個包含哈希的數組。 我想按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 ,因為它包含一個created_at值為 1 天前的item 接下來是group1 ,因為它包含一個值為 2 周前的項目, group2 將是最后一個,因為它最近的日期是一個月前。

如何重新排列這些數據?

我在想我可能不得不做類似的事情

 array_of_nested_hashes.each do |a|
      a.sort_by { |k, v| v[:created_at] }
 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"}]}, 
             ] 
  },
]

這是我的嘗試。 工作流程是:

1) 對所有內部數組進行排序,以獲得第一個索引的最大值(即最近的數字時間戳)。

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!

編輯:

這是對問題的正確解釋的答案:

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]的值。 同樣, arr[1]sort_by值為:

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

對於arr[2]是:

[30, 1, 7].min
  #=> 1

因此, arr排序為:

[arr[3], arr[1], arr[2]]

在知道它們實際上是時間戳之后..

這是我的答案

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

如果你有這個哈希,

{:z => { :z => 1 , :a => 3 }, :a => { :z => 6, :a => 7} }
a = {:z => { :z => 1 , :a => 3 }, :a => { :z => 6, :a => 7} }
a.each_with_object({}) { |e, hash| hash[e[0].to_sym] = e[1].sort.to_h }.sort.to_h

會給你..

 {:a=>{:a=>7, :z=>6}, :z=>{:a=>3, :z=>1}}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM