Jeremy Smith
Jeremy Smith

Reputation: 15069

Is there a way to conditionally add to an array in one line?

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

Answers (12)

maerics
maerics

Reputation: 156434

[str1, str2].reject {|x| x==''}
# ...or...
[str1, str2].reject &:empty?

Upvotes: 20

user16452228
user16452228

Reputation:

In a way, I feel like there are 2 different questions being asked:

  1. Is there a way to conditionally add to an array in one line?
  2. How do I achieve this specific task.

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

David Cook
David Cook

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

alexhayes
alexhayes

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

Tails
Tails

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

Solomons_Ecclesiastes
Solomons_Ecclesiastes

Reputation: 2099

Perhaps a more concise version of Cyril's answer:

Array.new.tap do |array| if condition array << "foo" end end

Upvotes: 1

Cyril Duchon-Doris
Cyril Duchon-Doris

Reputation: 13949

Object#tap

[: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

Yogesh Khater
Yogesh Khater

Reputation: 1958

Another way,

(str1.present? ? str1 : []) + [str2]

Upvotes: 1

kuriouscoder
kuriouscoder

Reputation: 5582

my_array = [str1, str2].find_all{|item| item != ""}

Upvotes: 0

LuisVM
LuisVM

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

sawa
sawa

Reputation: 168101

In ruby 1.9

[*(str1 unless str1.empty?), str2]

In ruby 1.8

[(str1 unless str1.empty?), str2].compact

Upvotes: 36

the Tin Man
the Tin Man

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

Related Questions