Filtering truthy values with select(&:itself)
Question
What is the return value of the following Ruby code?
a = [1, 2, nil, 2, "", false, 3]
a.select(&:itself) # => ???
The correct answer is
-
[1, 2, 3] -
[1, 2, nil, 2, "", false, 3] -
[1, 2, 2, "", 3]Correct -
[1, 2, 2, 3]
Explanation
TL;DR
select keeps the elements for which the block returns a truthy value, and &:itself turns each element into its own block result. In Ruby only nil and false are falsy, so those two are dropped and everything else survives, including the empty string: [1, 2, 2, "", 3].
Step by step
&:itself converts the symbol :itself into a block via Symbol#to_proc, so the call is equivalent to:
a = [1, 2, nil, 2, "", false, 3]
a.select { |x| x.itself } # => [1, 2, 2, "", 3]
Kernel#itself returns its receiver unchanged (42.itself # => 42), which makes the block an identity function: each element is judged by its own truthiness. nil and false are the only falsy values in Ruby, so 0 and "" count as truthy.
Edge cases
This idiom is stricter than compact and looser than Active Support's compact_blank:
a = [1, 2, nil, 2, "", false, 3]
a.select(&:itself) # => [1, 2, 2, "", 3]
a.compact # => [1, 2, 2, "", false, 3]
Array#compact removes only nil, so false and "" stay. Array#compact_blank (Active Support, Rails 6.1+) removes everything blank?: nil, false, "", empty arrays and hashes, and whitespace-only strings:
require "active_support/all"
a = [1, 2, nil, 2, "", false, 3]
a.compact_blank # => [1, 2, 2, 3]
Pick the one that matches the values you actually want to drop; they are not interchangeable.
Share this quiz
Comments
No comments yet. Be the first.