Reputation: 15069
I have str1 and str2. str1 may or not be an empty string, and I want to construct an array like:
str1 = ""
str2 = "bar"
["bar"]
or
str1 = "foo"
str2 = "bar"
["foo", "bar"]
I can only figure out a way to do this on two lines right now but I know there must be a way to do it one.
Upvotes: 21
Views: 14118
Reputation: 156434
[str1, str2].reject {|x| x==''}
# ...or...
[str1, str2].reject &:empty?
Upvotes: 20
Reputation:
In a way, I feel like there are 2 different questions being asked:
Regarding question #1:
Other people have already offered a lot of good options. One that I didn't see specifically mentioned though is that you can technically use a semicolon (;
) as an inline statement separator and basically write whatever you want on a single line of code. For example:
array = []; if x; array << a; elsif y; array << b; else; array << c; end; array
Regarding question #2:
Here's a fun option to to add to the list. Use the chomp(separator)
, split
, and reverse
methods.
str1 = ""
str2 = "bar"
"#{str2},#{str1}".chomp(",").split(",").reverse
#=> ["bar"]
str1 = "foo"
str2 = "bar"
"#{str2},#{str1}".chomp(",").split(",").reverse
#=> ["foo", "bar"]
string.chomp(substring)
with and without reverse
can be super handy ways to format string results that would otherwise need some conditional statements to handle the same operation somewhere else in the chain.
Upvotes: 0
Reputation: 563
A more compact way to do this is using presence
, which returns the object if present, or nil
if not.
nil
values can then be stripped with .compact
:
[str1.presence, str2].compact
or even better, the magical *
splat operator:
[*str1.presence, str2]
(And yes, pun was intended)
Upvotes: 1
Reputation: 789
Note that sawa's proposed answer for Ruby 1.9 (currently the answer with the most votes) has issues when used with a hash - as follows;
> [*({foo: 1} if true), {foo: 2}]
[
[0] [
[0] :foo,
[1] 1
],
[1] {
:foo => 2
}
]
Note that the compact example works as you would expect;
[({foo: 1} if true), {foo: 2}].compact
[
[0] {
:foo => 1
},
[1] {
:foo => 2
}
]
Upvotes: 2
Reputation: 712
You could monkey-patch Aray pr Enumerable and provide a conditional adding method.
module Array
def add_if(object, condition=true)
self << object if condition
return self
end
end
That way, it would be chainable, preserving most space in line.
array = [].add(:class, is_given?).add(object, false) #etc
Upvotes: -1
Reputation: 2099
Perhaps a more concise version of Cyril's answer:
Array.new.tap do |array|
if condition
array << "foo"
end
end
Upvotes: 1
Reputation: 13949
[:starting_element].tap do |a|
a << true if true
a << false if false
a << :for_sure
end
# => [:starting_element, true, :for_sure]
So in one line
[].tap { |a| [foo, bar].each { |thing| a << thing unless thing.blank? } }
[bar].tap { |a| a << bar unless foo.blank? }
Upvotes: 6
Reputation: 2793
You can use delete_if:
['', 'hola'].delete_if(&:empty?)
If you're using Rails, you can replace empty? by blank?
['', 'hola'].delete_if(&:blank?)
or use a block:
['', 'hola'].delete_if{ |x| x == '' }
Upvotes: 3
Reputation: 168101
In ruby 1.9
[*(str1 unless str1.empty?), str2]
In ruby 1.8
[(str1 unless str1.empty?), str2].compact
Upvotes: 36
Reputation: 160551
You can use a ternary statement:
ary = (str1.empty?) ? [ str2 ] : [ str1, str2 ]
str1 = ''; str2 = 'bar'
(str1.empty?) ? [ str2 ] : [ str1, str2 ] #=> ["bar"]
str1 = 'foo'; str2 = 'bar'
(str1.empty?) ? [ str2 ] : [ str1, str2 ] #=> ["foo", "bar"]
Upvotes: 0