Rail有条件地按自定义顺序循环哈希



我正在开发一个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 %>

这里有两个重要的概念:

  1. 使用Array#index查找在数组中找到元素的位置。
  2. "宇宙飞船运营商"<=>这就是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]所有不同元素对ghexample_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]一对不同的元素ghexample_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]]分配给空数组。

相关内容

  • 没有找到相关文章

最新更新