清理由nils

时间:2016-12-11 00:08:48

标签: arrays ruby null data-cleaning

例如我有一个数组:

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

清洁它的最佳方法是什么?数组必须只包含不包含nil的数组。清洁后必须:

[[1,2]]

类似的东西:

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

5 个答案:

答案 0 :(得分:3)

删除nil元素的数组上的方法称为compact。但是,这对于这种情况来说还不够,因为你有一个数组数组。此外,您需要select非零数组,或reject nil数组。您可以通过以下方式轻松地将两者结合起来:

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

仅当您有数组的子数组或nil时,这才有效。如果您的子数组包含两者,例如[1, nil, 2],然后此解决方案将保留整个子数组。

在迭代子数组时,可以改变子数组以删除nil,但是在迭代时可以认为实践是变异的。然而,这样做的方法是使用改变原始对象的compact方法的 bang 版本:

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

这将[[1, 2, nil, 3]]并返回[[1, 2, 3]]

正如sagarpandya82指出的那样,你也可以使用allany?方法来检查所有内容是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]]

答案 1 :(得分:3)

假设您只对2D阵列感兴趣,那么:

Rid子阵列仅包含nil s:

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

Rid子阵列由任何nil s组成:

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

答案 2 :(得分:3)

  • compact将从数组中删除nil个元素。
  • map将遍历数组中的每个项目,并通过在数组项上应用代码返回一个新数组。请注意,在您的示例中,数组的元素本身就是......数组。
  • reject将返回一个新数组,但不包含您给定代码回答的元素' false'到。
  • select将返回一个新数组,其中包含您的代码所喜欢的元素' (有点拒绝)。

因此,如果您只想从数组及其子数组(但不是子子数组)中删除所有nil s ,则可以调用

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 :(得分:3)

这个问题似乎有不同的解释。

如问题的示例所示,如果包含一个nil的所有元素(数组)仅包含nil s,并且要排除这些元素,则可以这样做:

[[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,则可以这样做:

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

如果要从每个元素中删除所有nil,然后删除所有空数组,则可以这样做:

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

答案 4 :(得分:0)

我最近在查看facets,这是一个ruby gem,它提供了许多核心ruby语言扩展。

他们给出的一个例子是Array#recurse方法,我将在下面显示:

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

在你的情况下,这大概完成了一半的工作 - 你也想删除非空数组。

Facets通过修补核心Ruby方法来工作。这意味着只要您运行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

测试出来:

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]]
相关问题