How to Find the Difference Between Two Arrays in Ruby
Ruby's Array#- is one of the cleanest one-liners in any language for this problem, but its exact behavior around duplicates is worth understanding precisely rather than guessing. Here are the four approaches worth knowing, in order of how often you'll actually reach for each.
Quick answer
a - b is the idiomatic one-liner - it removes every element of a that appears anywhere in b, while keeping a's own duplicates that aren't in b, and preserves a's original order. For symmetric difference, use (a - b) | (b - a). Ruby 2.6+ adds a.difference(b, c) to subtract multiple arrays in one call. For case-insensitive or custom comparison, use reject with a precomputed lowercase or Set lookup rather than calling include? on the raw array.
Need the same thing in another language?
See the full reference for Python, JavaScript, SQL, Java, and more.
a - b: the idiomatic one-liner
a = ["apple", "banana", "cherry", "banana"] b = ["banana", "date"] a_only = a - b puts a_only.inspect # ["apple", "cherry"] - both "banana"s removed since "banana" is in b; order preserved
Array#- removes every occurrence of an element from a if that element appears anywhere in b - so a repeated "banana" in a is entirely removed, not just reduced by one. Elements in a that aren't in b keep both their duplicates and their original position.
Symmetric difference: items in exactly one array
a = ["apple", "banana", "cherry"] b = ["banana", "date"] sym_diff = (a - b) | (b - a) puts sym_diff.inspect # ["apple", "cherry", "date"]
Ruby has no dedicated symmetric-difference operator, but combining both one-way differences with | (union, which also deduplicates) gets there in a single expression - everything unique to a plus everything unique to b.
difference(): subtracting multiple arrays at once (Ruby 2.6+)
a = ["apple", "banana", "cherry", "date"] b = ["banana"] c = ["date"] a_only = a.difference(b, c) puts a_only.inspect # ["apple", "cherry"]
Array#difference behaves exactly like chaining a - b - c, but reads more clearly when subtracting several arrays and avoids creating intermediate array objects for each subtraction step along the way.
Case-insensitive or custom-key difference with reject
a = ["Apple", "Banana", "Cherry"]
b = ["banana", "date"]
b_lower = b.map(&:downcase)
a_only = a.reject { |x| b_lower.include?(x.downcase) }
puts a_only.inspect
# ["Apple", "Cherry"] Array#- and Array#difference both use exact equality, so neither supports case-insensitive comparison directly. Precomputing b_lower once (rather than inside the block) avoids re-downcasing b on every element of a; for large arrays, wrap b_lower in a Set from Ruby's set library so include? is O(1) instead of a linear scan.
Just need the answer, not the code? Paste both lists.
Open Compare 2 Lists →Frequently Asked Questions
What does a - b actually do in Ruby when there are duplicates?
a - b removes every element from a that appears anywhere in b, regardless of how many times it appears in b - but it keeps all of a's own duplicates that aren't in b at all. So [1, 1, 2, 3] - [2] gives [1, 1, 3] - both 1's survive since 1 isn't in b, but if b contained a 1, both 1's in a would be removed.Does a - b preserve the original order of a?
Array#- preserves the order and any surviving duplicates of the original array a - it filters rather than converts to a set, even though it uses hashing internally for the O(n + m) lookup.How do I get the symmetric difference between two Ruby arrays?
(a - b) | (b - a). The | (union) operator also deduplicates the combined result, since union always returns unique elements.What does the difference() method do that - doesn't?
Array#difference (Ruby 2.6+) does the same thing as - but accepts multiple arrays in one call: a.difference(b, c, d) removes anything found in b, c, or d from a in a single expression, instead of chaining a - b - c - d.How do I do a case-insensitive array difference in Ruby?
a.reject { |x| b.map(&:downcase).include?(x.downcase) } works but re-downcases b on every iteration - precompute it once instead: b_lower = b.map(&:downcase); a.reject { |x| b_lower.include?(x.downcase) }. For large arrays, convert b_lower to a Set first so include? is O(1) instead of O(m).Is a - b slower than using Set for large arrays?
How do I find the difference between two arrays of hashes or objects in Ruby?
eql? and hash for equality, and Hash objects compare by content by default, so [{id: 1}] - [{id: 1}] already works as expected. For custom objects, override eql? and hash on the class, or extract just the comparison key first: ids_b = b.map(&:id); a.reject { |x| ids_b.include?(x.id) }.