Enumerator with index

Imagine a situation where you have a collection of string that you want to map to tag objects, but you want the first one to have a default flag.

first = true
tags = line.split(",").map do |name|
  tag = Tag.new(default: first, name: name)
  first = false
  tag
end

Alright, that works, but it’s not pretty. Is there a way to make it nicer?

Of course there is, at least for ruby 1.9.3 and higher. If you call a map method on a collection without any block it returns an Enumerator class since ruby 1.9.

And a method Enumerator#with_index that was introduced in ruby 1.9.3 adds an index to our iteration, so combining those two together we get

tags = line.split(",").map.with_index do |name, index|
  Tag.new(default: index == 0, name: tag_name)
end

Elegant and much easier to read. Enumerator is very powerful and helpful concept and with the combination of Enumerable module only the sky is the limit.

Also omitting the block and returning Enumerator instead of an array works not just for map, but for similar methods like select, reject, flat_map, group_by and others. Check out the docs and make your code nicer.

Resources


Did you like the article? Send me a comment!