Ruby: Getting Collect, Map, and Select Set Straight

Felice Forby - Oct 29 '18 - - Dev Community

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"]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!)

. . . . . . . . . . . . . . . . . . . . . . . . .