As I understand you are given an array order
that can be reordered to equal
example_statuses.map { |h| h[:status] }
#=> ["Active", "Pending", "Complete"]
and that you wish to sort example_statuses
to produce an array sorted
such that
sorted.map { |h| h[:status] } == order
#=> true
You do not need to actually sort example_statues
, which would have a computational complexity of O(n*log(n)
) where n
equals the number of elements in example_statuses
.
Instead, do the following, which has a computational complexity close to O(n
). Suppose
order = ["Pending", "Active", "Complete"]
Case 1: g[:status] != h[:status]
for all pairs of distinct elements g
and h
of example_statuses
In this case compute
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}]
The receiver of Hash#values_at is seen to be the following.
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}}
I earlier claimed that the computational complexity was "almost" O(n
). Building the hash example_statuses.each_with_object({}) { |g,h| h[g[:status]] = g }
is O(n
) but the key lookup for each element or order
is only "almost" O(1). Were is a constant time the complexity would be O(n
).
Case 2: g[:status] == h[:status]
for at least one pair of distinct elements g
and h
of example_statuses
Of course this case may not be permitted but that has not been made clear by the question.
Suppose order
is as before but example_statuses
is as follows.
example_statuses = [
{ :status => "Active", :job_count => 0 },
{ :status => "Pending", :job_count => 1},
{ :status => "Complete", :job_count => 3 },
{ :status => "Active", :job_count => 7 }
]
Note that example_statuses[0][:status]
and example_statuses[3][:status]
both equal "Active"
.
We need just a slight modification of the Case 1 calculation (which does not affect computational complexity).
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}]
The receivers of values_at
is seen to equal the following.
{"Active"=>[{:status=>"Active", :job_count=>0},
{:status=>"Active", :job_count=>7}],
"Pending"=>[{:status=>"Pending", :job_count=>1}],
"Complete"=>[{:status=>"Complete", :job_count=>3}]}
See the form of Hash::new that takes a block and no argument. When h
does not have a key [g[:status]
this causes h[g[:status]]
to be assigned to an empty array before executing g[:status]<< g
.