Ruby Yagi 🐐

Ruby, Rails, Web dev articles

Simplify loop using any?, all? and none?

by Axel Kee 23 September 2021

Ruby has some useful methods for enumerable (Array, Hash, etc), this post will talk about usage of any?, all?, and none?.

For examples used on this post, an Order model might have many Payment model (customer can pay order using split payments).

any?

To check if an order has any paid payments, a loop-based implementation might look like this :

has_paid_payment = false

order.payments.each do |payment|
  if payment.status == "paid"
    # one of the payment is paid
    has_paid_payment = true
    break
  end
end

if has_paid_payment
  # ...
end

We can simplify the code above using any? like this :

if order.payments.any?{ |payment| payment.status == 'paid'}
  # this will be executed if there is at least one paid payment
end

any? method can take in a block, and it will return true if the block ever returns a value that is not false or nil. (ie. true, or 123, or “abc”)

If no block is supplied, it will perform a self check for the elements:

order.payments.any?

# is equivalent to
order.payments.any? { |payment| payment }

all?

To check if all payments has been paid for an order, a loop-based implementation might look like this:

fully_paid = true

order.payments.each do |payment|
  if payment.status != "paid"
    # one of the payment is not paid, hence not fully paid
    fully_paid = false
    break
  end
end

if fully_paid
  # ...
end

We can simplify the code above using all? like this :

if order.payments.all?{ |payment| payment.status == 'paid'}
  # this will be executed if all payments are paid
end

all? method can take in a block, and it will return true if the block never returns a value that is false or nil for all of the elements.

If no block is supplied, it will perform a self check for the elements:

order.payments.all?

# is equivalent to
order.payments.all? { |payment| payment }

none?

This is the opposite of all?.

none? method accepts a block, and only returns true if the block never returns true for all elements.

if order.payments.none? { |payment| payment.status == 'paid' }
  # this will be executed if there is no paid payment for the order
end

If no block is supplied, it will perform a self check for the elements:

order.payments.none?

# is equivalent to
order.payments.none? { |payment| payment }

By utilizing any?, all? and none?, we can remove the usage of loop and make it more readable.

Reference

Ruby doc on enumeration