Удалить конечные значения nil из массива в ruby

У меня есть массив вроде этого:

[["a", nil, nil, nil], ["b", nil, "c", nil], [nil, nil, nil, nil]]

Я хочу удалить все конечные значения nil из массива в ruby.

Я пробовал arr.map {|x| x.pop until x.last}, но проблема с этим подходом заключается в том, что когда все значения массивов равны нулю, как в 3-м массиве в заданном массиве, цикл завершается.

Из-за условия until x.last, если все значения равны nil, тогда функция map должна вернуть мне пустой массив?

Какими должны быть условия для этого.

Выход должен быть

[['a'],['b','nil','c'],[]]

Помните, что я просто хочу удалить конечные значения nil, не находящиеся между ними.

Ответ 1

Для этого вы можете забыть о внешнем массиве и решить его только для внутренних массивов, а затем использовать map для применения решения для всех них.

drop_while вернет новый массив без всех ведущих элементов, которые удовлетворяли некоторому условию (например, nil?). Вы хотели, чтобы трейлинг сочетался с reverse.

[nil,nil,5,nil,6,nil].reverse.drop_while(&:nil?).reverse
[nil, nil, 5, nil, 6]

Затем используйте карту для всех массивов.

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"], []]

Если вы хотите, чтобы оставшаяся nil фактически была строкой, вы можете объединить ее с другой картой, выполняющей любое такое преобразование, которое вам нравится.

Ответ 2

Вы на правильном пути, но немного измените свой код:

array.each { |e| e.pop until !e.last.nil? || e.empty? }
#=> [["a"], ["b", nil, "c"], []]

Это быстрее, чем использование reverse - reverse и drop_while.

Ответ 3

Еще один вариант - использовать 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"], []]