Reputation: 4216
I'm looking for a more idiomatic way to filter out nil-or-empty elements of an array.
I have many methods of the form:
def joined
[some_method, some_other_method].compact.reject(&:empty?).join(' - ')
end
This will take the result of some_method
and some_other_method
and return only the one(s) that are both non-nil (compact
is essentially equivalent to reject(&:nil?)
) and non-empty.
Is there anything in Array or Enumerable that gets the same thing in one shot?
Upvotes: 23
Views: 14560
Reputation: 2348
ActiveSupport
, part of Rails, has this method, and so does the blank_empty_nil_filters
gem: is_blank?
and is_empty?
.
There is a distinction between the two. Some use-cases tolerate blanks (whitespace), some do not.
Perhaps most importantly, filtering out these kinds of values from Hash and Array values is already built-in to blank_empty_nil_filters
. Examples:
array.no_nil_values
array.no_empty_values
array.no_blank_values
See the README
ActiveSupport
a much larger, more comprehensive gem, uses Regexp.match
to determine blankness, while the blank_empty_nil_filters
gem code uses a non-destructive strip, which is both faster and less sensitive to non-UTF8 string error conditions.
Upvotes: 0
Reputation: 1548
I think you don't need to use reject
method. Simply use Array's select
method.
def joined
[some_method, some_other_method].select { |method| method.present? }
end
Or even better:
def joined
[some_method, some_other_method].select(&:present?)
end
For more Idiomatic way to write Ruby code, you should read this article
Upvotes: 0
Reputation: 8731
@trans enjoyed my +1 but after further deliberation I've reached the following conclusion.
If we go on the premise that everything is an Object
then all we actually need is a patch to class Object
class Object
def empty?
self == 0 or not self
end
end
Which satisfies my requirement:
1.9.3 :001 > d=[Object.new, Class, {a:nil}, 'a', '', [], 1, 1.1, 0, 0.0, 0x0, 0E0, true, false, nil]
=> [#<Object:0x007fd56c086918>, Class, {:a=>nil}, "a", "", [], 1, 1.1, 0, 0.0, 0, 0.0, true, false, nil]
1.9.3 :002 > d.reject(&:empty?)
=> [#<Object:0x007fd56c086918>, Class, {:a=>nil}, "a", 1, 1.1, true]
What about yours? Do we need something more? Please state your qualms or show silent agreement by voting up to help motivate a language change upstream.
nJoy!
Upvotes: 0
Reputation: 1441
Perhaps we need but one simple extension to NilClass?
class NilClass
def empty?
true
end
end
Upvotes: 2
Reputation:
monkeypatches accepted? :)
you can try this:
class Array
def tight
self.compact.reject { |i| i.size.zero? }
end
end
p [nil, 1, ''].tight
#=> [1]
p ['', nil, 2].tight
#=> [2]
it will work with any objects that responds to size
, not only with ones that respond to empty?
Upvotes: 2
Reputation: 2884
The following code should do the trick:
[some_method, some_other_method].reject{|i| i.nil? || i.empty? }
It could be easily used to extend the array class:
class Array
def purge
self.reject{|i| i.nil? || i.empty? }
end
end
And then you can just do:
[some_method, some_other_method].purge
Upvotes: 3
Reputation: 30445
In Rails, you can do reject(&:blank?)
, or equivalently, select(&:present?)
.
If this is not for a Rails app, and you do this a lot, I'd advise you to define your own helper on String
or whatever else you are filtering.
class String
alias :blank? :empty?
end
class NilClass
def blank?
true
end
end
Upvotes: 23