49

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.

potashin
  • 44,205
  • 11
  • 83
  • 107
  • I checked it, it doesn't have nil, how would you remove nil and empty string at the same time. How's it duplicate? –  Sep 30 '14 at 06:47
  • blank? returns true for both nil and '' (as well as other things like '/n'). [Docs link](http://api.rubyonrails.org/classes/Object.html#method-i-blank-3F) – Abraham Chan Sep 30 '14 at 06:48
  • 2
    Yes, `blank?` works but is not available in plain Ruby. It comes with Rails. – awendt Sep 30 '14 at 06:51
  • Abraham, that's in Rails not in Ruby. – Surya Sep 30 '14 at 06:51
  • Fair enough, I'll remove the duplicate. – Abraham Chan Sep 30 '14 at 06:52
  • 3
    Why downvote? people should atleast give an explanation of a downvote, is this how community help new people here? –  Sep 30 '14 at 06:58
  • `compact` returns new array, but leave the first array as it is (with `nil` inside). `compact!` changes existing array and returns it (if there will be no `nil` it returns nil). http://www.ruby-doc.org/core-2.0.0/Array.html#method-i-compact – RedZagogulin Sep 30 '14 at 07:02
  • @RedZagogulin I read it, the only issue was to remove blank strings and I didn't know about the other operations mentioned in the answers. My question was clear I think, have no idea why people go downvote for no reason without explaining anything. –  Sep 30 '14 at 07:05
  • 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. – awendt Sep 30 '14 at 07:09
  • @Зелёный blank won't work in Ruby, I hope you know that. :) –  Sep 30 '14 at 07:10
  • I've fixed this injustice for you. And yes, I agree that it would be nice if people will explain their downvotes. – RedZagogulin Sep 30 '14 at 07:12
  • @Зелёный I will, give beginners some time to breath. –  Sep 30 '14 at 07:15
  • Why was this question marked as a duplicate? It's clearly not a duplicate of the question referenced. – Cary Swoveland Jun 01 '15 at 16:45

13 Answers13

58

You could do this:

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

Note nil.to_s => ''.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • 8
    For those who see this answer first: as per https://stackoverflow.com/a/41810889/2441263, it's simpler to use `arr.reject(&:blank?)` – lucas Jul 22 '20 at 20:24
  • 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? – lucas Jul 24 '20 at 14:28
  • 2
    `:blank?`will only work in Rails as it is an ActiveSupport method and not a part of ruby. – pankajdoharey Aug 20 '20 at 09:57
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? }
Community
  • 1
  • 1
awendt
  • 13,195
  • 5
  • 48
  • 66
25

I tend to do:

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

returns:

=> [1, 2, "s", "d"]
JayJay
  • 746
  • 1
  • 9
  • 21
9

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

Marian13
  • 7,740
  • 2
  • 47
  • 51
8

arr.reject(&:blank?)

Just use this, no need to anything else.

Manindra Gautam
  • 387
  • 3
  • 8
  • 3
    `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. – Sebastián Palma Feb 08 '18 at 13:37
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

potashin
  • 44,205
  • 11
  • 83
  • 107
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 == "" }
RockStar
  • 1,304
  • 2
  • 13
  • 35
2

The simplest and fast way of doing this is :

arr = [1, 2, 's', nil, '', 'd'] - [nil,'']
==> arr = [1, 2, 's', 'd']
Jigar Panchal
  • 93
  • 3
  • 12
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"]
padmapriya
  • 11
  • 2
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"]
Surya
  • 15,703
  • 3
  • 51
  • 74
  • good use case, I'll keep this mind if I come across such situation in future. thanks. –  Sep 30 '14 at 07:14
0

try this out:

[1, 2, "s", nil, "", "d"].compact.select{|i| !i.to_s.empty?}
Sachin Singh
  • 7,107
  • 6
  • 40
  • 80
  • 1
    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". – Cary Swoveland Sep 30 '14 at 15:43
0

Hope this will work for your case :

arr = [1, 2, 's', nil, '', 'd']
arr.select{|x| x.to_s!="" }
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"]
Dom
  • 160
  • 2
  • 10