I have an array which contains hashes. I'd like to sort it by the created_at
value. Here's an example of the array structure:
我有一个包含哈希的数组。我想用created_at值对它进行排序。这是一个数组结构的例子:
Note, I've written human readable dates, the values will be a timestamp.
注意,我写了人类可读的日期,值将是一个时间戳。
[
{"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"}]},
]
}
]
I'd like to arrange the above data so the output would be group3
first, as it contains an item
with a created_at
value of 1 day ago. Next would be group1
as it contains an item with a value of 2 weeks ago, group2 would be last as it the most recent date is a month ago.
我想安排上面的数据,所以输出首先是group3,因为它包含一个创建日期值为1天的项目。接下来是group1,因为它包含一个值为2周前的项目,group2将是最后一个,因为它最近的日期是一个月前。
How can I rearrange this data?
我该如何重新排列这些数据?
I was thinking I might have to do something like
我以为我可能要做类似的事情
array_of_nested_hashes.each do |a|
a.sort_by { |k, v| v[:created_at] }
end
to sort the data within each group by date, then sort each group by the date of it's first hash - as that would be the most recent hash in each group, giving me the fully sorted hash, which would look like this:
按日期对每个组内的数据进行排序,然后按照第一个哈希的日期对每个组进行排序 - 这将是每个组中最新的哈希值,给出完全排序的哈希值,如下所示:
[
{"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"}]},
]
},
]
3 个解决方案
#1
Here's my attempt. The worflow is:
这是我的尝试。这个问题是:
1) Sort all inner arrays to get the biggest value (meaning most recent numeric timestamp) to the first index.
1)对所有内部数组进行排序,以获得第一个索引的最大值(意味着最近的数字时间戳)。
2) With the biggest value in a known position (index 0) in the inner array, sort the outer arrays according the value of the the first index in their inner array.
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!
#2
Edit:
Here's an answer for the correct interpretation of the question:
以下是对问题的正确解释的答案:
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"=>...}]
Most of the explanation below applies to this answer as well.
以下大多数解释也适用于此答案。
tidE
This is one way you could do it, letting arr
denote the array of hashes you wish to sort.
这是你可以做到的一种方式,让arr表示你想要排序的哈希数组。
Code
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"}]}]}]
Explanation
The sorting can be done by converting each date string to numbers of days. We begin by assigning a variable to the enumerator arr.sort_by
. We can then use Enumerator#next to obtain each value of the enumerator, which we then pass to the block.
可以通过将每个日期字符串转换为天数来完成排序。我们首先将一个变量赋给枚举器arr.sort_by。然后我们可以使用Enumerator#next来获取枚举数的每个值,然后我们将其传递给块。
enum = arr.sort_by
#=> #<Enumerator:
# [{"group1"=>[{:item1=>
# [{"name"=>"Tim", "created_at"=>"4 weeks ago"}]},...
# :sort_by>
Now assign the first value of the enumerator to the block variable:
现在将枚举数的第一个值分配给块变量:
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
passes the first element of arr
to the block, assigning it to the block variable:
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
Similarly, the second and third elements of arr1
are mapped to 21
and 14
(days), respectively. We then compute:
类似地,arr1的第二和第三个元素分别映射到21和14(天)。然后我们计算:
[28, 21, 14].min
#=> 14
which is the value sort_by
uses for arr[0]
. Similarly, the sort_by
values for arr[1]
are:
这是sort_by用于arr [0]的值。同样,arr [1]的sort_by值为:
[30, 60, 120].min
#=> 30
and for arr[2]
are:
对于arr [2]是:
[30, 1, 7].min
#=> 1
Therefore, arr
is sorted to:
因此,arr被排序为:
[arr[3], arr[1], arr[2]]
#3
After knowing that they are actually timestamps ..
知道它们实际上是时间戳之后..
here's my answer
这是我的答案
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
#1
Here's my attempt. The worflow is:
这是我的尝试。这个问题是:
1) Sort all inner arrays to get the biggest value (meaning most recent numeric timestamp) to the first index.
1)对所有内部数组进行排序,以获得第一个索引的最大值(意味着最近的数字时间戳)。
2) With the biggest value in a known position (index 0) in the inner array, sort the outer arrays according the value of the the first index in their inner array.
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!
#2
Edit:
Here's an answer for the correct interpretation of the question:
以下是对问题的正确解释的答案:
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"=>...}]
Most of the explanation below applies to this answer as well.
以下大多数解释也适用于此答案。
tidE
This is one way you could do it, letting arr
denote the array of hashes you wish to sort.
这是你可以做到的一种方式,让arr表示你想要排序的哈希数组。
Code
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"}]}]}]
Explanation
The sorting can be done by converting each date string to numbers of days. We begin by assigning a variable to the enumerator arr.sort_by
. We can then use Enumerator#next to obtain each value of the enumerator, which we then pass to the block.
可以通过将每个日期字符串转换为天数来完成排序。我们首先将一个变量赋给枚举器arr.sort_by。然后我们可以使用Enumerator#next来获取枚举数的每个值,然后我们将其传递给块。
enum = arr.sort_by
#=> #<Enumerator:
# [{"group1"=>[{:item1=>
# [{"name"=>"Tim", "created_at"=>"4 weeks ago"}]},...
# :sort_by>
Now assign the first value of the enumerator to the block variable:
现在将枚举数的第一个值分配给块变量:
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
passes the first element of arr
to the block, assigning it to the block variable:
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
Similarly, the second and third elements of arr1
are mapped to 21
and 14
(days), respectively. We then compute:
类似地,arr1的第二和第三个元素分别映射到21和14(天)。然后我们计算:
[28, 21, 14].min
#=> 14
which is the value sort_by
uses for arr[0]
. Similarly, the sort_by
values for arr[1]
are:
这是sort_by用于arr [0]的值。同样,arr [1]的sort_by值为:
[30, 60, 120].min
#=> 30
and for arr[2]
are:
对于arr [2]是:
[30, 1, 7].min
#=> 1
Therefore, arr
is sorted to:
因此,arr被排序为:
[arr[3], arr[1], arr[2]]
#3
After knowing that they are actually timestamps ..
知道它们实际上是时间戳之后..
here's my answer
这是我的答案
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