按值对哈希数组排序
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
,因为它包含一个 item
和 1 天前的 created_at
值。接下来是 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!
在知道它们其实是时间戳之后..
这是我的答案
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
编辑:
下面是对问题正确解读的答案:
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"=>...}]
下面的大部分解释也适用于这个答案。
tidE
这是您可以做到的一种方法,让 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"}]}]
map
将 arr
的第一个元素传递给块,将其分配给块变量:
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
的第二个和第三个元素分别映射到21
和14
(天)。然后我们计算:
[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]]
如果你有这个散列,
{: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}}
我有一个包含散列的数组。我想按 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 天前的 created_at
值。接下来是 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!
在知道它们其实是时间戳之后..
这是我的答案
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
编辑:
下面是对问题正确解读的答案:
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"=>...}]
下面的大部分解释也适用于这个答案。
tidE
这是您可以做到的一种方法,让 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"}]}]
map
将 arr
的第一个元素传递给块,将其分配给块变量:
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
的第二个和第三个元素分别映射到21
和14
(天)。然后我们计算:
[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]]
如果你有这个散列,
{: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}}