Mega Man
Mega Man

Reputation: 297

How to filter out empty elements in arrays

I have a line of code that iterates over an array and rejects any empty elements:

survey.reject!(&:empty?).map! { |feedback| %(_"#{feedback}"_) }

If the entire array is empty, this works as expected. If one of the elements in the array is not empty I get an error map! doesn't exist.

This, however, has no problems:

survey.map! { |feedback| %(_"#{feedback}_") }

The reject function works when the entire array is empty, and map! version works when the array isn't empty. How can I best consolidate these?

Upvotes: 1

Views: 187

Answers (2)

Jörg W Mittag
Jörg W Mittag

Reputation: 369428

Array#reject! returns nil if it didn't change anything. nil doesn't have a map! method, so you get a NoMethodError.

Why are you chaining side-effecting methods anyway? The purpose of a side-effecting method is its side-effect, not its return value. You can just do

survey.reject!(&:empty?)
survey.map! { |feedback| %(_"#{feedback}"_) }

Or, better yet: don't use side-effects. They're evil.

survey = survey.reject(&:empty?).map { |feedback| %(_"#{feedback}"_) }

Note, however, that this does not do the same thing as the above: the above mutates the single object that is referenced by survey. This mutates the reference survey itself and makes it point to a different object.

This is cleaner overall, but if there is other code in your system that depends on mutable shared state and side-effects, it will have to be changed, too.

Upvotes: 3

tadman
tadman

Reputation: 211540

You've got to be careful when using in-place modifiers. As the documentation for reject! says:

Deletes every element of self for which the block evaluates to true, if no changes were made returns nil.

Due to that feature, you can't chain these like you can the versions that reliably make copies.

What you can do is do it on two lines:

survey.reject!(&:empty?)
survey.map! { |feedback| %(_"#{feedback}"_) }

Or you can chain-reassign:

survey = survey.reject(&:empty?).map { |feedback| %(_"#{feedback}"_) }

Upvotes: 4

Related Questions