☰
×
Jonathan ThomBlogProjectsContact

Benchmarking Arrays Full of Nils

2.17.2019


What is the fastest way in Ruby to check if all values of an array are nil?

I had this question recently when writing some display logic. If the record didn't have any of the desired values available, it would not be shown, but if it had at least one, it would. The gist of what I was trying to accomplish was this:

    class SomePresenterClass
        def show_info?
            # The object has 10 values, attr1 through attr10.
            # If one is non-nil, return true
            # else return false
        end
    end

    # show.slim
    - if @some_presenter_instance.show_info?
        # show some cool stuff
    - else
        # N/A

There were three candidates I could think of.

    array = [attr1, attr2, attr3, etc... attr10]

    # Option 1
    # Iterate thought each item, and only return true if all are nil.
    def show_info?
        array.all? { |a| a.nil? }
    end

    # Option 2
    # Remove all items with .compact, and see if there's anything left in the array.
    def show_info?
        arr.compact.empty?
    end

    # Option 3
    # Includes an implicit { |a| a } block, returns true if any of the items is not nil or false
    def show_info?
        arr.any?
    end

I thought I was very clever with that compact one, but when we run the benchmarks, there is a clear winner.

    require "benchmark"

    arr = [nil] * 10000
    n = 5000

    Benchmark.bmbm do |x|
      x.report("compact") { n.times do; arr.compact.empty?; end }
      x.report("all?")  { n.times do; arr.all?(&:nil?); end  }
      x.report("any?")  { n.times do; arr.any?; end  }
    end

                  user     system      total        real
    all?      1.943716   0.003502   1.947218 (  1.953412)
    compact   0.065184   0.000185   0.065369 (  0.065653)
    any?      0.024278   0.000057   0.024335 (  0.024408)

In a landslide, .any? was the fastest!

I have a couple of caveats. First, looking at any array of 10,000 nils is not a super realistic scenario (I don't think??), at least for what I was doing. Second, if you did want to return true if one of the values was false, you'd need to go with .compact instead. And finally, all of this ignores the fact that there is a database involved! This is all moot if you hit Postgres a million times. Although perhaps there's a way to get at this with one big elegant SQL query.

Do you have any other clever (and faster) ways to approach this? Email me!

Other Posts

The Best Projects Can Be Done in a Weekend

Everyone Has Something To Offer

Book Thoughts: Capital and Ideology

Naive Diffie-Hellman Implementation in Ruby

PGP/GPG

Lessons from Sandi Metz

When Does the Magic Comment Work, and When Does it Not?

Go, and When It's Okay to Learn New Things

Favorite Talks from RailsConf

Grouping Records by Month with Ruby

Front End Refactor

Add Timestamps to Existing Tables in Rails

Let Your Projects Breathe

The Busy and (Somewhat) Fit Developer

TuxedoCSS and the Rails Asset Pipeline

Gem You Should Know About: auto_html

Querying for Today's Date with ActiveRecord

Getting the Action Mailer to Actually Mail (with Mailgun)

Advice for New Epicodus Students