-
-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposal] Performance/SelectFirst #63
Comments
Can you show a benchmark compared to alternative methods? |
Obviously the difference scales with the size of the array. require 'benchmark/ips'
array = 100_000.times.map { rand > 0.1 ? 0 : 1 } # 10% of the array should be 1, 90% should be 0
Benchmark.ips do |x|
x.report("slow") { array.select(&:nonzero?).first }
x.report("fast") { array.find(&:nonzero?) }
x.compare!
end
=begin
Warming up --------------------------------------
slow 3.000 i/100ms
fast 44.899k i/100ms
Calculating -------------------------------------
slow 35.648 (±11.2%) i/s - 177.000
fast 579.702k (±14.2%) i/s - 2.829M
Comparison:
fast: 579701.7 i/s
slow: 35.6 i/s - 16262.05x slower
=end But even with a much smaller array it's still significant: require 'benchmark/ips'
array = 100.times.map { rand > 0.1 ? 0 : 1 } # 10% of the array should be 1, 90% should be 0
Benchmark.ips do |x|
x.report("slow") { array.select(&:nonzero?).first }
x.report("fast") { array.find(&:nonzero?) }
x.compare!
end
=begin
Warming up --------------------------------------
slow 3.172k i/100ms
fast 29.762k i/100ms
Calculating -------------------------------------
slow 33.738k (±13.5%) i/s - 168.116k
fast 397.477k (±12.9%) i/s - 1.964M
Comparison:
fast: 397477.5 i/s
slow: 33737.8 i/s - 11.78x slower
=end |
This one is less exciting, it's just neater code IMO: require 'benchmark/ips'
array = 100_000.times.map { rand > 0.1 ? 0 : 1 } # 10% of the array should be 1, 90% should be 0
Benchmark.ips do |x|
x.report("slow") { array.select(&:nonzero?).count }
x.report("fast") { array.count(&:nonzero?) }
x.compare!
end
=begin
Warming up --------------------------------------
slow 3.000 i/100ms
fast 3.000 i/100ms
Calculating -------------------------------------
slow 37.756 (± 2.6%) i/s - 189.000
fast 35.935 (±11.1%) i/s - 180.000
Comparison:
slow: 37.8 i/s
fast: 35.9 i/s - same-ish: difference falls within error
=end |
Thank you for benchmarking with alternative methods. I agree to add this cop to performance cops. I will convey some of points considered.
Why did I choose this fix out of the possible options?I think that coding context will be maintained by replacing # Use `select { ... }.first`
Model.select { |model| model.attr == value }.first #=> Returns an AR model object
# Use `find { ... }`
Model.find { |model| model.attr == value } #=> Returns an AR model object
# Use `delect { ... }`
Model.delect { |model| model.attr == value } #=> NoMethodError
NoMethodError: undefined method `delect' for #<Class:0x007f81bd065ae0>
Did you mean? delete
select So I considered that it should be replaced by |
It may be possible to further consider whether it is okay to include Cc @rubocop-hq/rubocop-core |
I think that was caused by a typo: Both |
Yeah, |
Is there a recommended approach to having rules only apply to specific ruby versions? |
Please use |
I think |
@ghiculescu Have you started work on this? |
Ahh, no I haven't. @fatkodima if you're interested please go ahead, otherwise I will try and get to it soon. |
We have built this cop internally, for identifying uses of
.select {}.first
or.select {}.count
that could be written in a more performant way. My question is, would rubocop accept a PR to add this to the main gem (if I added tests etc) or is it too niche?The text was updated successfully, but these errors were encountered: