Reputation: 114138
What's the most idiomatic way to create an array from several variables without nil
values?
Given these variables:
a = 1
b = nil
c = 3
I would like to create an array ary
:
ary #=> [1, 3]
I could use Array#compact
:
ary = [a, b, c].compact
ary #=> [1, 3]
But putting everything in an array just to remove certain elements afterwards doesn't feel right.
Using if
statements on the other hand produces more code:
ary = []
ary << a if a
ary << b if b
ary << c if c
ary #=> [1, 3]
Is there another or a preferred way or are there any advantages or drawbacks using either of the above?
PS: false
doesn't necessarily have to be considered. The variables are either truthy (numbers / strings / arrays / hashes) or nil
.
Upvotes: 4
Views: 896
Reputation: 1
Here is a solution that uses a hash.
With these values put in an array:
a = 1; b = nil; c = 3; d = nil; e = 10;
ary = [a, b, c, d, e]
There are two nil items in the result which would require a compact
to remove both "nil" items.
However the same variables added to a hash:
a = 1; b = nil; c = 3; d = nil; e = 10;
hash = {a => nil, b => nil, c => nil, d => nil, e => nil}
There is just one "nil" item in the result which can easily be removed by hash.delete(nil)
.
Upvotes: 0
Reputation: 114138
I was hoping for a way to somehow "skip" the nil
values during array creation. But after thinking about this for a while, I realized that this can't be achieved because of Ruby's way to handle multiple values. There's no concept of a "list" of values, multiple values are always represented as an array.
If you assign multiple values, Ruby creates an array:
ary = 1, nil, 3
#=> [1, nil, 3]
Same for a method taking a variable number of arguments:
def foo(*args)
args
end
foo(1, nil, 3)
#=> [1, nil, 3]
So even if I would patch Array
with a class method new_without_nil
, I would end up with:
def Array.new_without_nil(*values)
values.compact!
values
end
This just moves the code elsewhere.
From an OO point of view, there's nothing special about nil
- it's an object like any other. Therefore, removing nil
's is not different from removing 1
's.
Using a bunch of if
statements on the other hand is something I'm trying to avoid when writing object oriented code. I prefer sending messages to objects.
[...]
with compact
/ compact!
[...]
with <<
and if
statements
I'll use compact
, might have been obvious.
Upvotes: 2
Reputation: 1157
If you are concerned about performance, best way would be probably to use destructive #compact!
to avoid allocating memory for second array.
Upvotes: 4