Array#include?
arr.include?(object) → true or false Array#include? returns true when any element of the array is == to the argument, and false otherwise. It is the Ruby equivalent of “does this list contain X” — a direct membership test that short-circuits on the first match. It is the search method most Ruby code reaches for when checking whether a value is in an array.
[1, 2, 3].include?(2) # => true
[1, 2, 3].include?(4) # => false
["a", "b"].include?("c") # => false
[].include?("anything") # => false
The scan walks elements left-to-right and stops at the first match, but the return value is always a plain boolean. If you need the matching element itself, use Array#find instead. If you need a block form (for predicates, regex matches, or attribute checks), use Array#any? instead.
Also called member?
Array#member? is an alias of include? inherited from Enumerable. They are the same method under two names, so method(:include?) == method(:member?) returns true on any array. member? exists because include? is part of the enumerable contract for any collection that mixes in the module; Array simply keeps the same name for both. Pick the spelling you prefer and stick with it; include? is the more common form in the Ruby community.
[:draft, :published].include?(:draft) # => true
[:draft, :published].member?(:published) # => true
Equality semantics
include? uses Object#== for comparison. That gives the behavior most readers expect for built-in types — 1 == 1, "x" == "x", :a == :a — and applies recursively to nested arrays and hashes. These are the same equality semantics used by Array#uniq, Array#-, and the rest of the array methods, so results stay consistent across the API.
[[1, 2], [3, 4]].include?([1, 2]) # => true
[{ a: 1 }, { a: 2 }].include?({ a: 1 }) # => true
A few consequences worth knowing:
- No type coercion.
[1].include?("1")isfalsebecause1 == "1"isfalsein Ruby. Symbols and strings are not interchangeable:[:draft].include?("draft")is alsofalse. NaNis never “in” the array.Float::NAN == Float::NANisfalse, soinclude?will never find aNaNeven when one is in the array:[1.0, Float::NAN, 2.0].include?(Float::NAN) # => false- Custom classes need
==. The defaultObject#==is identity comparison, so two distinct instances with the same attributes are not equal unless the class overrides==(or includesComparableand defines<=>):class Role include Comparable attr_reader :name def initialize(name) = @name = name def ==(other) = other.is_a?(Role) && other.name == name def <=>(other) = name <=> other.name end [Role.new("admin"), Role.new("owner")].include?(Role.new("admin")) # => true
Performance
Array#include? is O(n). MRI implements the scan in C (rb_ary_include_p), so it skips the per-element Ruby method dispatch that Enumerable#include? would do, but it still has to walk the array element by element.
For repeated lookups against a stable collection, build a Set once and use set.include?(x) for O(1) checks. This turns the membership test from a linear search into a hash-backed lookup:
require "set"
ALLOWED = Set.new(%w[admin editor viewer])
ALLOWED.include?("admin") # => true
ALLOWED.include?("owner") # => false
Calling arr.include?(x) inside a loop that iterates arr is O(n²). Build the Set once at the top of the method, then look up against it. The threshold where Set starts winning depends on array size and lookup frequency, but a few hundred lookups against a few hundred elements is usually the point where the conversion pays for itself.
Common mistakes
Using include? on a hash and expecting a value check. Hash#include? tests for keys, not values. Use hash.value?(v) (or hash.has_value?(v)) to test whether a value is present. The two methods share a name in the standard library but have very different semantics, and the confusion is one of the most common gotchas in Ruby code review.
Passing a regex. include? does not accept a block. To test whether any element matches a pattern, use any? with a block, or grep if you want the matching elements back. The block form is also what you want when the search predicate is more complex than == — for example, matching by attribute, by a computed key, or by a substring check:
names = ["alice", "bob", "alex"]
names.any? { |n| n.start_with?("al") } # => true
names.grep(/^al/) # => ["alice", "alex"]
Splats and “is any of these values in the array?” include? takes exactly one argument, so arr.include?(*[:a, :b]) becomes arr.include?([:a, :b]) and asks whether the array [:a, :b] is itself an element — almost never what the caller wanted. To test whether any of several values is present, intersect the two arrays and check whether the result is non-empty. The & operator is Array#intersection, which walks both arrays and returns the values they share; if the result is empty, none of the required values is in the source, and if non-empty, at least one of them is. This form is often the clearest way to phrase the membership question because the code reads like the question you are actually asking.
roles = %w[admin editor viewer]
(roles & %w[admin owner]).any? # => true
Or test every required value explicitly with all?. Use all? when the requirement is that all of the values must be present — think “must have every one of these” — and use intersection.any? when the requirement is that at least one of them must be present — think “must have at least one of these”. The two forms read differently and answer different questions, so pick the one whose shape matches the requirement you are encoding:
required = %w[admin editor]
required.all? { |r| roles.include?(r) } # => true
See Also
Array#any?— block-form predicate when you need more than==.Array#find— returns the matching element instead of a boolean.Hash#include?— same name, different semantics (keys only).