In one of my Flatiron coding challenges, I had to make an anagram tester that would test which words in an array were anagrams of the target word. Possible anagrams were passed to a #match
method through an array. The #match
method would then be called on an Anagram object and “collect” all the words that matched as an anagram. For example:
listen = Anagram.new("listen")
listen.match(%w(enlists google inlets banana))
# => ["inlets"]
As I wanted to “collect” all the matches, at first I attempted to use #collect
on the array.
class Anagram
attr_accessor :word
def initialize(word)
@word = word
@letters = @word.split("").sort
end
# find anagram matches given an array of words
def match(possible_anagrams)
possible_anagrams.collect do |possible_anagram|
@letters == possible_anagram.split("").sort
end
end
end
The problem with #collect
, however, is that it collects all of the return values produced by the code in the block, so I was getting an array full of the values that were returned by the block's expression.
With #collect
, the listen.match(%w(enlists google inlets banana))
was returning => [false, false, true, false]
. What I really needed was to get just the items in the array that made the code block return true.
Guess who can do that? You guessed it: #select
! Switching out #collect
for #select
solved the problem:
class Anagram
attr_accessor :word
def initialize(word)
@word = word
@letters = @word.split("").sort
end
# find anagram matches given an array of words
def match(possible_anagrams)
possible_anagrams.select do |possible_anagram|
@letters == possible_anagram.split("").sort
end
end
end
Now only the items that made the block true would be included in the returned array: => ["inlets"].
The difference is super clear if you check the Ruby documentation:
- #collect: “Creates a new array containing the values returned by the block.”
- #select: “Returns a new array containing all elements of the array for which the given block returns a true value.”
Okay, so what about #map
? It turns out #map is the exact same thing as #collect. A lot of times you’ll hear that certain functions do the same thing, but in truth there are actually slight differences. In the case of #map
and #collect
, though, they are identical down to the source code. Check for yourself by clicking the “click to toggle source” under the #collect and #map documentation!
Edit: Initial code refactored based on discussion comments below (thank you!)
Top comments (1)
Ah, good catch on splitting the word too many times. It would definitely be better to split the word in the initialize method so it's only done once. Also, yes, the block does not need to return "real" values - your suggestion would simplify the code. I'll fix this up based on your feedback. Thank you!