Skip to content

Enumerable

Frank Koehl edited this page Apr 17, 2015 · 2 revisions

Extensions to Enumerable

Enumerable#key_map

key_map(key)

Standard Enumerable#map has a great shortcut when you want to create an Array by calling a method on each element in the collection. For example:

class Pokemon
  attr_accessor :name
  def initialize(n)
    @name = n
  end
end

your_pokedex = [
  Pokemon.new("Bulbasaur"),
  Pokemon.new("Charmander"),
  Pokemon.new("Squirtle"),
]

If you want an Array of Pokemon names, you use Enumerable#map:

your_pokedex.map { |p| p.name }
# => ["Bulbasaur", "Charmander", "Squirtle"]

A shortcut makes it easy for trivial, repeatable method calls (such as to :name):

your_pokedex.map(&:name)
# => ["Bulbasaur", "Charmander", "Squirtle"]

But what happens when my Pokedex isn't as well-structured as yours?

my_pokedex = [
  {name: "Bulbasaur"},
  {name: "Charmander"},
  {name: "Squirtle"},
]

I can still map the :name keys out to an Array with full block notation...

my_pokedex.map { |p| p[:name] }
# => ["Bulbasaur", "Charmander", "Squirtle"]

But such sad! I can haz no shortcut.

my_pokedex.map(??????)
# => ["Bulbasaur", "Charmander", "Squirtle"]

Enter Enumerable#key_map:

my_pokedex.key_map(:name)
# => ["Bulbasaur", "Charmander", "Squirtle"]

Enumerable#key_map_reduce

key_map_reduce(key, arg = :+, &block)

Building off of Enumerable#key_map, finishing_moves provides a convenience method when you need to perform a one-step map/reduce operation on a collection.

my_pokedex = [
  {name: "Bulbasaur",   level: 2},
  {name: "Charmander",  level: 2},
  {name: "Squirtle",    level: 2},
]

In other words, this map/reduce operation

my_pokedex.key_map(:level).reduce(0) { |memo,lvl| memo + lvl }
# => 6

can be simplified to

my_pokedex.key_map_reduce(:level, :+)
# => 6

where :+ can be any named method of memo, and is applied to each value (just as in Enumerable#reduce). For additional flexibility, you can pass an intial value for memo and a custom block (and again, this works just like Enumerable#reduce):

my_pokedex.key_map_reduce(:level, 0) { |memo,lvl| memo + lvl }
# => 6
Clone this wiki locally