2016-12-11 7 views
4

Например, у меня есть массив:Очистка Массивы Массивы, которые состоят из Nils

[[nil, nil], [1, 2], [nil, nil], [nil, nil]] 

Что это лучший способ, чтобы очистить его? Массив должен иметь только массивы, которые не состоят из нуля. После очистки она должна быть:

[[1,2]] 

Что-то вроде:

[[nil, nil], [1, 2], [nil, nil], [nil, nil]].each {|x| x - [nil]} 
+0

насчет подрешетки '[1 , 2, ноль, 3] '? –

ответ

3

Методы массивов, удаляющих nil элементов называется compact. Однако этого недостаточно для этой ситуации, потому что у вас есть массив массивов. Кроме того, вы захотите, чтобы select не-nil-массивы, или reject массивы, которые являются nil. Вы можете легко объединить два следующим образом:

[[nil, nil], [1, 2], [nil, nil], [nil, nil]].reject { |arr| arr.compact.empty? }

Это будет работать только если у вас есть вложенные массивы чисел или nil с. Если ваши вспомогательные массивы содержат как, например, [1, nil, 2], тогда это решение будет поддерживать весь вспомогательный массив.

Модифицировать вспомогательный массив можно, удаляя nil, в то время как вы перебираете вспомогательные массивы, но это может считаться практикой мутировать, пока вы итерации. Тем не менее, способ сделать это было бы использовать паф версию compact метода, который мутирует исходный объект в:

.reject { |arr| arr.compact!.empty? }

Это займет [[1, 2, nil, 3]] и вернуть [[1, 2, 3]].

Как sagarpandya82 отметил, вы можете также использовать all или any? методы просто проверить, все ли nil, или если что-то nil вместо удаления nil с.

Резюмируя:

original_array = [[nil, nil],[1, nil, 2], [1, 2, 3]] 
original_array.reject { |arr| arr.all?(:nil) } # returns [[1, nil, 2], [1, 2, 3]] 
original_array.reject { |arr| arr.compact.empty? } # returns [[1, nil, 2], [1, 2, 3]] 
original_array.reject { |arr| arr.any?(:nil) } # returns [[1, 2, 3]] 
original_array.reject { |arr| arr.compact!.empty? } # returns [[1, 2, 3], [1, 2]] 
+0

было бы неплохо увидеть рекурсивный способ сделать это, хотя –

+0

Это звучало так, что OP хотел, чтобы метод цепочки решения, но рекурсивное решение, безусловно, можно выполнить с помощью вызова метода. – Dbz

3

Предполагая, что вы заинтересованы только в 2D-массивах:

Rid суб-массивы, состоящие только nil с:

arr.reject { |arr| arr.all?(&:nil?) } 

Rid суб- массивы, состоящие из любых nil с:

arr.reject { |arr| arr.any?(&:nil?) } 
3
  • compact удалит nil элементы из массива.
  • map будет работать над каждым элементом массива и возвращать новый массив, применяя код к элементу массива.Обратите внимание, что в вашем примере элементы массива являются собой ... Массивы.
  • reject вернет новый массив без элементов, которые ваш данный код отвечает «false».
  • select вернет новый массив с элементами, которые ваш данный код «любит» (вид противоположности отклонения).

Так что, если вы просто хотите удалить все nil ы из массива и его подмассива (но не под-подрешетки), вы могли бы назвать

list = [[1,2], [nil], [1,nil,2]] 
list.map(&:compact).reject(&:empty?) #=> [[1,2], [1,2]] 

, который так же, как

compacted_list = list.map do |element| 
    element.compact 
end 
non_empty_list = compacted_list.reject do |element| 
    element.empty? 
end 

Если вы хотите Удалить все [nil, nil] записи из списка/массива

list.reject{|element| element == [nil, nil]} 

или если он больше о выборе элементов, не нулевые (это на самом деле просто о намерении раскрывающейся код)

list.select{|element| element != [nil, nil]) 

Большинство этих функций иметь ! аналог (например, reject!), который делает модификация на месте, что означает, что вам не нужно назначать возвращаемое значение (например, в new_list = old_list.reject()).

3

По-видимому, существуют разные толкования вопроса.

Если, как это было предложено, например на вопрос, все элементы (массивы), которые содержат один nil содержат только nil с, и эти элементы должны быть исключены, то это сделать:

[[nil, nil], [1, 2], [nil, nil], [nil, nil]].select(&:first) 
    #=> [!1, 2]] 

Если все элементы которые содержат, по меньшей мере, один nil должны быть исключены, то это сделать:

[[3, nil], [1, 2], [3, 4, 5, nil]].reject { |a| a.any?(&:nil?) } 
    #=> [!1, 2]] 

Если все nil s должны быть удалены из каждого элемента, это будет сделать это:

[[3, nil], [1, 2], [nil], [nil, 3, 4]].map(&:compact) 
    #=> [[3], [1, 2], [], [3, 4]] 

Если все nil s должны быть удалены из каждого элемента, а затем все пустые массивы должны быть удалены, это будет сделать это:

[[3, nil], [1, 2], [nil], [nil, 3, 4]].map(&:compact).reject(&:empty?) 
    #=> [[3], [1, 2], [3, 4]] 
+1

что есть '&: первый' делать? :) –

+0

@SunilD., Это фактически то же самое, что и 'arr.select {| pair | pair.first} '. 'pair.first' является правдивым, если он не равен ни« ниль », ни« ложному ». Следовательно, элемент '[a, b]' выбирается, если 'a' является правдивым. Я предполагаю из примера в вопросе, что 'b' является' nil' тогда и только тогда, когда 'a' является' nil'. –

0

Я недавно смотрел на facets, рубин который обеспечивает множество основных расширений языка рубинов.

Одним из примеров, которые они дают для метода Array#recurse, я покажу ниже:

arr = ["a", ["b", "c", nil], nil] 
arr.recurse{ |a| a.compact! } 
#=> ["a", ["b", "c"]] 

Это получает около полдела сделано в вашем случае - вы также хотите удалить непустые массивы.

Facets работает путем исправления основных рубиновых методов. Это означает, что как только вы запустите require 'facets/array/recurse', любой ранее определенный метод Array#recurse будет переопределен.Исправление основных методов обычно не рекомендуется из-за возможности конфликтов имен.

Тем не менее, это полезный метод, и его легко определить таким образом, что он принимает массив как аргумент вместо того, чтобы работать с значением self. После этого вы можете использовать его, чтобы определить два метода, которые вместе выполнить свою цель:

module ArrayUtils 
    def recurse(array, *types, &block) 
    types = [array.class] if types.empty? 
    a = array.reduce([]) do |arr, value| 
     case value 
     when *types 
     arr << recurse(value, *types, &block) 
     else 
     arr << value 
     end 
     arr 
    end 
    yield a 
    end 

    def recursive_compact(array) 
    recurse(array, &:compact) 
    end 

    def recursive_remove_nonempty(array) 
    recurse(array) do |arr| 
     arr.reject do |x| 
     x.is_a?(Array) && x.empty? 
     end 
    end 
    end 
end 

Testing это:

include ArrayUtils 

orig = [[nil, nil], [1, 2], [nil, nil], [nil, nil]] 
compacted = recursive_compact(orig) 
nonempties = recursive_remove_nonempty compacted 

puts "original: #{orig.inspect}" 
puts "compacted: #{compacted.inspect}" 
puts "nonempties: #{nonempties.inspect}" 

и работает

original: [[nil, nil], [1, 2], [nil, nil], [nil, nil]] 
compacted: [[], [1, 2], [], []] 
nonempties: [[1, 2]] 

 Смежные вопросы

  • Нет связанных вопросов^_^