Reputation: 1161
What is the common way when you want to initialize an Array with optional elements in ruby/rails?
Right now I do
array = []
array << "1st element"
array << "2nd element" if flag?
array << "3rd element"
but It feels very verbose and I am guessing it could be slower than when initialized altogether
I'd like to know if there is something like,
array = [
"1st element",
"2nd element" if flag?,
"3rd element",
]
#=> ["1st element", "3rd element"]
Upvotes: 2
Views: 1136
Reputation: 114138
You can achieve this by using the splat operator *
:
array = [
"1st element",
*("2nd element" if flag?),
"3rd element"
]
This works because *"2nd element"
returns the string and *nil
effectively removes itself:
["1st element", *"2nd element", "3rd element"]
#=> ["1st element", "2nd element", "3rd element"]
["1st element", *nil, "3rd element"]
#=> ["1st element", "3rd element"]
Note that *
attempts to call to_a
so this might have undesired effects if your objects implements that method: (this is Time#to_a
)
["1st element", *Time.now, "3rd element"]
#=> ["1st element", 56, 43, 11, 15, 10, 2020, 4, 289, true, "CEST", "3rd element"]
Upvotes: 0
Reputation: 110675
I would emphasize clarity and generality.
a = [1,2,3]
b = [4,5,6]
c = [7,8,9]
def concat_some(*arr)
arr.reduce([]) { |ar,(a,flag)| flag ? ar.concat(a) : ar }
end
concat_some([a,true], [b,false], [c,true])
#=> [1, 2, 3, 7, 8, 9]
concat_some([a,false], [b,true], [c,false])
#=> [4, 5, 6]
or
def concat_for_indices(*arr, indices)
indices.reduce([]) { |a,i| a.concat(arr[i]) }
end
concat_for_indices(a,b,c,[1,2])
#=> [4, 5, 6, 7, 8, 9]
concat_for_indices(a,b,c,[2])
#=> [7, 8, 9]
concat_for_indices(a,b,c,[])
#=> []
concat_for_indices(a,b,c,[0,1,2])
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
or
def concat_except_for_indices(*arr, indices)
((0..arr.size-1).to_a - indices).reduce([]) { |a,i| a.concat(arr[i]) }
end
concat_except_for_indices(a,b,c, [0])
#=> [4, 5, 6, 7, 8, 9]
concat_except_for_indices(a,b,c, [1,2])
#=> [1, 2, 3]
concat_except_for_indices(a,b,c, [])
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
concat_except_for_indices(a,b,c, [0,1,2])
#=> []
Upvotes: 1
Reputation: 101811
While this doesn't quite do it at initialization you can always insert the elements afterwards if you know the index:
array = ["1st element", "3rd element"]
array.insert(1, "2nd element") if flag?
Or a bit more elegantly:
array = ["1st element", "3rd element"].tap { |a| a.insert(1, "2nd element") if flag? }
The advantage here being that it does not compact the array in case you actually intend to have nil values.
Upvotes: 1
Reputation: 5895
Though it's not a good idea, but you can do something like this in ruby/rails:
flag = true
["1st element", eval("'2nd element' if flag"), "3rd element"].compact
# output: ["1st element", "2nd element", "3rd element"]
Upvotes: 0
Reputation: 1385
I'm not sure if this is a good way of doing it, but here's my suggestion:
array = [
"1st element",
flag? ? "2nd element" : nil,
"3rd element"
].compact
.compact
will remove all the nil
values from your array. This will be problematic if you might have nil values.
Upvotes: 3