Reputation: 1494
I have an array something like this:
[["a", nil, nil, nil], ["b", nil, "c", nil], [nil, nil, nil, nil]]
I want to remove all trailing nil values from array in ruby.
I tried arr.map {|x| x.pop until x.last}
but the problem with this approach is that when all the value of arrays are nil like in 3rd array in given array, the loop stucks.
Because of the until x.last
condition, If all the values are nil then the map function should return me an empty array?
What should be the conditions for this.
The output should be
[['a'],['b','nil','c'],[]]
Remember I just want to remove trailing nil
values not in between.
Upvotes: 13
Views: 1134
Reputation: 13477
One more option is to use rindex
:
arr.map do |e|
index = e.rindex { |i| !i.nil? } # the last index of not `nil` element
index ? e.first(index + 1) : e
end
#=> [["a"], ["b", nil, "c"], []]
Upvotes: 4
Reputation: 13477
You are on the right way, but just modify your code a bit:
array.each { |e| e.pop until !e.last.nil? || e.empty? }
#=> [["a"], ["b", nil, "c"], []]
It's faster than using reverse
-reverse
and drop_while
.
Upvotes: 10
Reputation: 30115
For this you can forget about the outer array and solve it for just the inner arrays, then use map
to apply the solution to all of them.
drop_while
will return a new array without all leading items that met some condition (e.g. nil?
). You wanted trailing however so combine with reverse
.
[nil,nil,5,nil,6,nil].reverse.drop_while(&:nil?).reverse
[nil, nil, 5, nil, 6]
Then use map for all the arrays.
arr = [["a", nil, nil, nil], ["b", nil, "c", nil], [nil, nil, nil, nil]]
arr.map{|a| a.reverse.drop_while(&:nil?).reverse}
[["a"], ["b", nil, "c"], []]
If you do want any remaining nil
to actually be a string, you could combine it with another map performing any such conversion you like.
Upvotes: 14