52

I am new to Ruby and stuck with this issue. Let's say I have an array like this:

arr = [1, 2, 's', nil, '', 'd']

and I want to remove nil and blank string from it, i.e. final array should be:

arr = [1, 2, 's', 'd']

I tried compact but it gives this:

arr.compact!
arr #=> [1, 2, 's', '', 'd'] doesn't remove empty string.

I was wondering if there's a smart way of doing this in Ruby.

13
  • I checked it, it doesn't have nil, how would you remove nil and empty string at the same time. How's it duplicate? Commented Sep 30, 2014 at 6:47
  • blank? returns true for both nil and '' (as well as other things like '/n'). Docs link Commented Sep 30, 2014 at 6:48
  • 2
    Yes, blank? works but is not available in plain Ruby. It comes with Rails. Commented Sep 30, 2014 at 6:51
  • 3
    Why downvote? people should atleast give an explanation of a downvote, is this how community help new people here? Commented Sep 30, 2014 at 6:58
  • 3
    @anInteger I don't understand the downvotes either. It's not a duplicate (which IMO is never a reason to downvote anyway), the question is clearly stated and it's clear that you tried to find your own solution. Commented Sep 30, 2014 at 7:09

13 Answers 13

60

You could do this:

arr.reject { |e| e.to_s.empty? } #=> [1, 2, "s", "d"]

Note nil.to_s => ''.

Sign up to request clarification or add additional context in comments.

3 Comments

For those who see this answer first: as per stackoverflow.com/a/41810889/2441263, it's simpler to use arr.reject(&:blank?)
Ah! Thanks Cary, my mistake! I was moving too fast and didn't see that comment on the linked answer. Still hope my comment helps rushed folks like me who got here by googling the best way to do this in rails. Maybe not the place for this question, but why the preference for referencing a handle (that can change) over linking directly to the answer?
:blank?will only work in Rails as it is an ActiveSupport method and not a part of ruby.
28

I tend to do:

arr = [1, 2, 's', nil, '', 'd']
arr.reject(&:blank?)

returns:

=> [1, 2, "s", "d"]

1 Comment

It wouldn't work as blank? doesn't work on integer or nil class.
27

Since you want to remove both nil and empty strings, it's not a duplicate of How do I remove blank elements from an array?

You want to use .reject:

arr = [1, 2, 's', nil, '', 'd']
arr.reject { |item| item.nil? || item == '' }

NOTE: reject with and without bang behaves the same way as compact with and without bang: reject! and compact! modify the array itself while reject and compact return a copy of the array and leave the original intact.

If you're using Rails, you can also use blank?. It was specifically designed to work on nil, so the method call becomes:

arr.reject { |item| item.blank? }

6 Comments

Integer does not respond to empty?
Oh. You're absolutely right. Thanks for pointing this out. I updated the answer.
can't upvote because of the low reputation but this is also a nice answer. Also, thank you for the tip but I am not using Rails for now. :)
This is the answer I upvote. The way I like to use it is as arr.reject &:blank?.
For older versions of ruby you can use empty? instead of blank?
|
18

compact_blank (Rails 6.1+)

If you are using Rails (or a standalone ActiveSupport), starting from version 6.1, there is a compact_blank method which removes blank values from arrays.

It uses Object#blank? under the hood for determining if an item is blank.

[1, 2, 's', nil, '', 'd'].compact_blank
# => [1, 2, 's', 'd']

[1, "", nil, 2, " ", [], {}, false, true].compact_blank
# => [1, 2, true]

Here is a link to the docs and a link to the relative PR.

A destructive variant is also available. See Array#compact_blank!.

1 Comment

Good find! Gives us another good reason to upgrade to Rails 6.1.
8

arr.reject(&:blank?)

Just use this, no need to anything else.

1 Comment

blank isn't a Ruby method, it's a Rails one, so you should add the active_support needed library, and the question has tagged Ruby not Rails. Anyways, this answer states something pointed before.
4

You can also use - to remove all nil and '' elements:

arr -= [nil, '']
#=> [1, 2, "s", "d"]

Demonstration

Or compact and reject with shortcut (in case you are not using Rails where you can just use arr.reject(&:blank?) ):

arr = arr.compact.reject(&''.method(:==))
#=> [1, 2, "s", "d"]

Demonstration

Comments

2

You can use compact with reject

arr = [1, 2, 's', nil, '', 'd']
arr = [1, 2, 's', 'd']

arr = arr.compact.reject { |h| h == "" }

or

arr = arr.compact.delete_if { |h| h == "" }

Comments

2

The simplest and fast way of doing this is :

arr = [1, 2, 's', nil, '', 'd'] - [nil,'']
==> arr = [1, 2, 's', 'd']

Comments

1

You can use compact and delete_if method to remove nil and blank string in an array in Ruby

arr = [1, 2, 's', nil, '', 'd']
arr.compact!.delete_if{|arrVal| arrVal.class == String and arrVal.empty?}
=> [1, 2, "s", "d"]

Comments

0

try this out:

[1, 2, "s", nil, "", "d"].compact.select{|i| !i.to_s.empty?}

1 Comment

You might consider using reject, rather than select, bot to get rid of ! and because compact is also a form of rejection. To me, "reject this and reject that" reads better than "reject this and select that".
0

Note: I am considering the array might have string with white spaces in it.

You can do:

arr = [1, 2, 's', nil, ' ', 'd']
arr.reject{|a| a.nil? || (a.to_s.gsub(' ', '') == '') }
#=> [1, 2, "s", "d"]

or:

arr.reject{|a| a.nil? || (a.to_s.gsub(' ', '').empty?) }
#=> [1, 2, "s", "d"]

or if you want to update arr object itself then:

arr.reject!{|a| a.nil? || (a.to_s.gsub(' ', '') == '') } # notice the ! mark, it'll update the object itself.
p arr #=> [1, 2, "s", "d"]

1 Comment

good use case, I'll keep this mind if I come across such situation in future. thanks.
0

Hope this will work for your case :

arr = [1, 2, 's', nil, '', 'd']
arr.select{|x| x.to_s!="" }

Comments

0

I would probably add .strip to eliminate potential whitespace headaches (assuming its not a rails app).

array = [1, 2, "s", nil, "     ", "d", "\n"]
array.reject!{|a| a.nil? || (a.to_s.strip.empty?) }

#=> [1, 2, "s", "d"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.