rarefying array with limit
I have array of objects form AR I want to rarefy them, with limit.
Current method looks like:
def rarefied_values(limit = 200)
all_values = self.values.all
rarefied_values = []
chunk_size = (all_values.size / limit.to_f).ceil
if all_values.size > limit
开发者_开发百科 all_values.each_slice(chunk_size) do |chunk|
rarefied_values.push(chunk.first)
end
return rarefied_values
else
return all_values
end
end
Any hints for refactoring?
def rarefied_values(limit = 200)
all_values = values.all
return all_values unless all_values.size > limit
chunk_size = all_values.size / limit
(0...limit).map{|i| all_values[i*chunk_size]}
end
Some general points in refactoring in ruby
self
can be omitted usually. In a few cases, you cannot, for exampleself.class
. In this case,self.values.all
=>values.all
- If one of the conditioned procedures is much simpler compared to the others, then place that simple case first, and get rid of it from the rest of the code using
return
. In this case,return all_values unless all_values.size > limit
- In general, when you need nested conditions, design it so that cases with simpler procedures split off eariler, and the complicated cases are placed toward the end.
- Let the code be lazy as possible. In this case,
rarefied_values = []
is not necessary ifall_values.size > limit
. So put that in the conditioned section.
Here's a naïve refactor, keeping your same methods, but removing the explicit return calls and only performing certain transformations if necessary:
def rarefied_values(limit = 200)
all_values = self.values.all
if all_values.size <= limit
all_values
else
chunk_size = (all_values.size / limit.to_f).ceil
[].tap{ |rare| all_values.each_slice(chunk_size){ |c| rare << c.first } }
end
end
Here's a faster, more terse version:
def rarefied_values(limit = 200)
all_values = self.values.all
if (size = all_values.size) <= limit
all_values
else
all_values.values_at(*0.step(size-1,(size.to_f/limit).ceil))
end
end
精彩评论