我正在开发一个RoR Web应用程序。
我必须根据哈希值以自定义顺序循环哈希数组。
在此示例中,"待处理"状态需要首先显示在列表中。
是否可以自定义每个循环中数组的顺序?
<% example_statuses = [{ :status => "Active", :job_count => 0 }, { :status => "Pending", :job_count => 1 }, { :status => "Complete", :job_count => 3 }] %>
<% example_statuses.each do |es| %>
<h3><%= es[:status] %></h3>
<% end %>
更新: 我有一个简单的工作示例,涉及将挂起的状态哈希删除并预置回数组中。但是,有没有办法创建自定义订单而不是手动逐个替换值?
<% example_statuses = [{ :status => "Active", :job_count => 0 }, { :status => "Pending", :job_count => 1 }, { :status => "Complete", :job_count => 3 }] %>
<%= pending = example_statuses.find { |x| x[:status] == "Pending"} %>
<% example_statuses.delete(pending) %>
<% example_statuses.prepend(pending) %>
<% example_statuses.each do |es| %>
<h3><%= es[:status] %></h3>
<% end %>
这里有两个重要的概念:
- 使用
Array#index
查找在数组中找到元素的位置。 - "宇宙飞船运营商"
<=>
这就是Array#sort
的工作方式。你可以在这里调查它
在您的情况下,解决方案将是:
example_statuses = [{ :status => "Active", :job_count => 0 }, { :status => "Pending", :job_count => 1 }, { :status => "Complete", :job_count => 3 }]
order = ["Pending", "Active", "Complete"]
sorted_array = example_statuses.sort do |a,b|
order.index(a[:status]) <=> order.index(b[:status])
end
# => [{:status=>"Pending", :job_count=>1}, {:status=>"Active", :job_count=>0}, {:status=>"Complete", :job_count=>3}]
你可以像这样用单行尝试example_statuses.sort_by{|x| x[:status] == 'Pending' ? '' : x[:status] }
据我了解,您将获得一个数组order
可以重新排序为相等
example_statuses.map { |h| h[:status] }
#=> ["Active", "Pending", "Complete"]
并且您希望对example_statuses
进行排序以生成一个数组sorted
以便
sorted.map { |h| h[:status] } == order
#=> true
你不需要实际对example_statues
进行排序,这将具有O(n*log(n)
)的计算复杂度,其中n
等于example_statuses
中的元素数。
相反,请执行以下操作,其计算复杂度接近 O(n
)。假设
order = ["Pending", "Active", "Complete"]
情况 1:g[:status] != h[:status]
所有不同元素对g
和h
example_statuses
在这种情况下,计算
example_statuses.each_with_object({}) { |g,h| h[g[:status]] = g }
.values_at(*order)
#=> [{:status=>"Pending", :job_count=>1},
# {:status=>"Active", :job_count=>0},
# {:status=>"Complete", :job_count=>3}]
Hash#values_at 的接收者如下所示。
example_statuses.each_with_object({}) { |g,h| h[g[:status]] = g }
#=> {"Active"=>{:status=>"Active", :job_count=>0},
# "Pending"=>{:status=>"Pending", :job_count=>1},
# "Complete"=>{:status=>"Complete", :job_count=>3}}
我早些时候声称计算复杂度"几乎"为O(n
)。构建哈希example_statuses.each_with_object({}) { |g,h| h[g[:status]] = g }
是 O(n
),但每个元素或order
的键查找只有"几乎"O(1)。WAS 是一个常数时间,复杂度为 O(n
)。
情况 2:至少g[:status] == h[:status]
一对不同的元素g
和h
example_statuses
当然,这种情况可能不被允许,但这个问题还没有明确说明。
假设order
和以前一样,但example_statuses
如下。
example_statuses = [
{ :status => "Active", :job_count => 0 },
{ :status => "Pending", :job_count => 1},
{ :status => "Complete", :job_count => 3 },
{ :status => "Active", :job_count => 7 }
]
请注意,example_statuses[0][:status]
和example_statuses[3][:status]
都等于"Active"
。
我们只需要对案例 1 计算稍作修改(这不会影响计算复杂性)。
example_statuses.each_with_object(Hash.new { |h,k| h[k] = [] }) do |g,h|
h[g[:status]] << g
end.values_at(*order).flatten
#=> [{:status=>"Pending", :job_count=>1},
# {:status=>"Active", :job_count=>0},
# {:status=>"Active", :job_count=>7},
# {:status=>"Complete", :job_count=>3}]
values_at
的接收者被视为等于以下内容。
{"Active"=>[{:status=>"Active", :job_count=>0},
{:status=>"Active", :job_count=>7}],
"Pending"=>[{:status=>"Pending", :job_count=>1}],
"Complete"=>[{:status=>"Complete", :job_count=>3}]}
请参阅Hash::new的形式,它需要一个块并且没有参数。当h
没有键[g[:status]
这会导致在执行g[:status]<< g
之前将h[g[:status]]
分配给空数组。