Yay for recursion :)

Recursion is usually inefficient in Ruby, but in this case with a small
number of elements it is actually faster. Nothing earth-shaking, but it
is fun to see recursion come out ahead once in a while in Ruby-land.
Yay!

Benchmark.ips do |x|
  array = ['updated_at desc', 'first_name asc', 'date desc']

  def parse_sort(field)
    attr_name, new_dir = field.to_s.split(/\s+/)
    "#{attr_name} #{new_dir}"
  end

  def recursive_add(array)
    return [] if array.empty?
    [parse_sort(array[0])] + recursive_add(array.drop 1)
  end

  def inject_add(array)
    array.inject([]) { |a, field| a + [parse_sort(field)] }
  end

  def inject_append(array)
    array.inject([]) { |a, field| a << parse_sort(field) }
  end

  def each_with_object_append(array)
    array.each_with_object([]) { |field, a| a << parse_sort(field) }
  end

  x.report('recursive +') do |times|
    i = 0
    while i < times
      recursive_add(array)
      i += 1
    end
  end

  x.report('inject +') do |times|
    i = 0
    while i < times
      inject_add(array)
      i += 1
    end
  end

  x.report('inject <<') do |times|
    i = 0
    while i < times
      inject_append(array)
      i += 1
    end
  end

  x.report('each_with_object <<') do |times|
    i = 0
    while i < times
      each_with_object_append(array)
      i += 1
    end
  end

  x.compare!
end

Base case 1 element (array = ['updated_at desc’]):

∴ rake benchmarks:inject_versus_recursive
Calculating -------------------------------------
recursive +    12.732k i/100ms
inject +    11.834k i/100ms
inject <<    12.096k i/100ms
each_with_object <<    12.535k i/100ms
-------------------------------------------------
recursive +    361.342k (±11.6%) i/s -      1.782M
inject +    275.680k (±10.8%) i/s -      1.373M
inject <<    330.712k (± 9.1%) i/s -      1.645M
each_with_object <<    345.253k (± 8.1%) i/s -      1.717M

Comparison:
recursive +:   361341.9 i/s
each_with_object <<:   345253.4 i/s - 1.05x slower
inject <<:   330712.3 i/s - 1.09x slower
inject +:   275679.5 i/s - 1.31x slower

With 3 elements (array = ['updated_at desc', 'first_name asc', 'date
desc']):

∴ rake benchmarks:inject_versus_recursive
Calculating -------------------------------------
recursive +     8.590k i/100ms
inject +     8.292k i/100ms
inject <<     8.776k i/100ms
each_with_object <<     8.665k i/100ms
-------------------------------------------------
recursive +    151.233k (± 2.8%) i/s -    755.920k
inject +    135.586k (± 4.3%) i/s -    679.944k
inject <<    144.773k (± 5.8%) i/s -    728.408k
each_with_object <<    147.728k (± 5.6%) i/s -    736.525k

Comparison:
recursive +:   151233.3 i/s
each_with_object <<:   147727.8 i/s - 1.02x slower
inject <<:   144772.9 i/s - 1.04x slower
inject +:   135586.4 i/s - 1.12x slower
This commit is contained in:
Jon Atack 2014-12-14 14:49:00 +01:00
parent 5fd42f6c7e
commit 0783af7644
1 changed files with 4 additions and 5 deletions

View File

@ -85,7 +85,7 @@ module Ransack
if Hash === @default_order
@default_order = @default_order.with_indifferent_access
end
@sort_params = initialize_sort_params(search, sort_fields)
@sort_params = build_sort(search, sort_fields)
@sort_params = @sort_params.first if @sort_params.size == 1
end
@ -145,10 +145,9 @@ module Ransack
{}.with_indifferent_access
end
def initialize_sort_params(search, sort_fields)
sort_fields.reduce([]) do |array, field|
array + [parse_sort(search, field)]
end
def build_sort(search, fields)
return [] if fields.empty?
[parse_sort(search, fields[0])] + build_sort(search, fields.drop(1))
end
def parse_sort(search, field)