Skip to content
  • Ricardo Díaz's avatar
    de154095
    Replace usage of `Array#?` with `Array#intersect?` for efficiency · de154095
    Ricardo Díaz authored
    `Array#intersect?` was introduced in Ruby 3.1.0 and it's more efficient and
    useful when the result of the intersection is not needed as the
    following benchmarks show:
    
    ```
    require "bundler/inline"
    
    gemfile(true) do
      source "https://rubygems.org"
    
      git_source(:github) { |repo| "https://github.com/#{repo}.git" }
    
      gem "rails", path: "./"
      # If you want to test against edge Rails replace the previous line with this:
      # gem "rails", github: "rails/rails", branch: "main"
      gem "benchmark-ips"
    end
    
    require "active_support"
    
    SCENARIOS = [
      [(1..100).to_a, (90..200).to_a],    # Case 1
      [("a".."m").to_a, ("j".."z").to_a], # Case 2
      [(1..100).to_a, (101..200).to_a],   # Case 3
    ]
    
    SCENARIOS.each_with_index do |values, n|
      puts
      puts " Case #{n + 1} ".center(80, "=")
      puts
      Benchmark.ips do |x|
        x.report("Array#?") { !(values[0] & values[1]).empty? }
        x.report("Array#intersect?")      { values[0].intersect?(values[1]) }
        x.compare!
      end
    end
    ```
    
    Results:
    
    ```
    ==================================== Case 1 ====================================
    
    ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin21]
    Warming up --------------------------------------
                 Array#?    34.221k i/100ms
        Array#intersect?    62.035k i/100ms
    Calculating -------------------------------------
                 Array#?    343.119k (± 1.1%) i/s -      1.745M in   5.087078s
        Array#intersect?    615.394k (± 1.1%) i/s -      3.102M in   5.040838s
    
    Comparison:
        Array#intersect?:   615393.7 i/s
                 Array#?:   343119.4 i/s - 1.79x  slower
    
    ==================================== Case 2 ====================================
    
    ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin21]
    Warming up --------------------------------------
                 Array#?   103.256k i/100ms
        Array#intersect?   185.104k i/100ms
    Calculating -------------------------------------
                 Array#?      1.039M (± 1.3%) i/s -      5.266M in   5.066847s
        Array#intersect?      1.873M (± 1.6%) i/s -      9.440M in   5.041740s
    
    Comparison:
        Array#intersect?:  1872932.7 i/s
                 Array#?:  1039482.4 i/s - 1.80x  slower
    
    ==================================== Case 3 ====================================
    
    ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin21]
    Warming up --------------------------------------
                 Array#?    37.070k i/100ms
        Array#intersect?    41.438k i/100ms
    Calculating -------------------------------------
                 Array#?    370.902k (± 0.8%) i/s -      1.891M in   5.097584s
        Array#intersect?    409.902k (± 1.0%) i/s -      2.072M in   5.055185s
    
    Comparison:
        Array#intersect?:   409901.8 i/s
                 Array#?:   370902.3 i/s - 1.11x  slower
    ```
    de154095
    Replace usage of `Array#?` with `Array#intersect?` for efficiency
    Ricardo Díaz authored
    `Array#intersect?` was introduced in Ruby 3.1.0 and it's more efficient and
    useful when the result of the intersection is not needed as the
    following benchmarks show:
    
    ```
    require "bundler/inline"
    
    gemfile(true) do
      source "https://rubygems.org"
    
      git_source(:github) { |repo| "https://github.com/#{repo}.git" }
    
      gem "rails", path: "./"
      # If you want to test against edge Rails replace the previous line with this:
      # gem "rails", github: "rails/rails", branch: "main"
      gem "benchmark-ips"
    end
    
    require "active_support"
    
    SCENARIOS = [
      [(1..100).to_a, (90..200).to_a],    # Case 1
      [("a".."m").to_a, ("j".."z").to_a], # Case 2
      [(1..100).to_a, (101..200).to_a],   # Case 3
    ]
    
    SCENARIOS.each_with_index do |values, n|
      puts
      puts " Case #{n + 1} ".center(80, "=")
      puts
      Benchmark.ips do |x|
        x.report("Array#?") { !(values[0] & values[1]).empty? }
        x.report("Array#intersect?")      { values[0].intersect?(values[1]) }
        x.compare!
      end
    end
    ```
    
    Results:
    
    ```
    ==================================== Case 1 ====================================
    
    ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin21]
    Warming up --------------------------------------
                 Array#?    34.221k i/100ms
        Array#intersect?    62.035k i/100ms
    Calculating -------------------------------------
                 Array#?    343.119k (± 1.1%) i/s -      1.745M in   5.087078s
        Array#intersect?    615.394k (± 1.1%) i/s -      3.102M in   5.040838s
    
    Comparison:
        Array#intersect?:   615393.7 i/s
                 Array#?:   343119.4 i/s - 1.79x  slower
    
    ==================================== Case 2 ====================================
    
    ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin21]
    Warming up --------------------------------------
                 Array#?   103.256k i/100ms
        Array#intersect?   185.104k i/100ms
    Calculating -------------------------------------
                 Array#?      1.039M (± 1.3%) i/s -      5.266M in   5.066847s
        Array#intersect?      1.873M (± 1.6%) i/s -      9.440M in   5.041740s
    
    Comparison:
        Array#intersect?:  1872932.7 i/s
                 Array#?:  1039482.4 i/s - 1.80x  slower
    
    ==================================== Case 3 ====================================
    
    ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin21]
    Warming up --------------------------------------
                 Array#?    37.070k i/100ms
        Array#intersect?    41.438k i/100ms
    Calculating -------------------------------------
                 Array#?    370.902k (± 0.8%) i/s -      1.891M in   5.097584s
        Array#intersect?    409.902k (± 1.0%) i/s -      2.072M in   5.055185s
    
    Comparison:
        Array#intersect?:   409901.8 i/s
                 Array#?:   370902.3 i/s - 1.11x  slower
    ```
Loading