Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 完成一个Ruby数组_Arrays_Ruby_Null - Fatal编程技术网

Arrays 完成一个Ruby数组

Arrays 完成一个Ruby数组,arrays,ruby,null,Arrays,Ruby,Null,我的应用程序需要处理固定大小的数组。问题是,有时元素为零,但零是一个禁止值。我认为一个简单的方法是用最接近的非nil值(就在前面或后面)替换nil值 nil值可以是第一个、最后一个,甚至是倍数。以下是我正在寻找的一些例子: [1,2,3,nil,5] => [1,2,3,3,5] [nil,2,3,4,5] => [2,2,3,4,5] [1,nil,nil,4,5] => [1,1,4,4,5] 我相信有一种优雅的方法可以做到这一点。您能帮忙吗?首先,将每个元素与下一个和上

我的应用程序需要处理固定大小的数组。问题是,有时元素为零,但零是一个禁止值。我认为一个简单的方法是用最接近的非nil值(就在前面或后面)替换nil值


nil值可以是第一个、最后一个,甚至是倍数。以下是我正在寻找的一些例子:

[1,2,3,nil,5] => [1,2,3,3,5]
[nil,2,3,4,5] => [2,2,3,4,5]
[1,nil,nil,4,5] => [1,1,4,4,5]

我相信有一种优雅的方法可以做到这一点。您能帮忙吗?

首先,将每个元素与下一个和上一个元素配对

triples = array.zip([nil]+array.take(array.length-1), array.drop(1))
然后映射到三元组数组上,如下所示:

triples.map {|triple|
  if triple[0].nil? then
    if !triple[1].nil? then triple[1] else triple[2] end
  else
    triple[0]
  end
}
如果一行中有超过2个零,这将不起作用,因此将其放入循环中并继续调用它,直到数组中没有更多的零

编辑(Jörg W Mittag):通过使用解构bind和guard子句,您可以使其更加简洁易读:

ary.zip([nil] + ary.take(ary.length-1), ary.drop(1)).map {|prv, cur, nxt|
  next prv unless prv.nil?
  next cur unless cur.nil?
  nxt
}
如果以这种方式重构,很容易看出块所做的一切都是在前一个当前下一个三元组中查找第一个非
nil
元素,可以更简洁地表示为:

ary.zip([nil] + ary.take(ary.length-1), ary.drop(1)).map {|triple|
  triple.find {|el| !el.nil? }
}

反过来,可以通过使用
Array#compact

进一步简化这一过程。首先,将每个元素与下一个和上一个元素配对

triples = array.zip([nil]+array.take(array.length-1), array.drop(1))
然后映射到三元组数组上,如下所示:

triples.map {|triple|
  if triple[0].nil? then
    if !triple[1].nil? then triple[1] else triple[2] end
  else
    triple[0]
  end
}
如果一行中有超过2个零,这将不起作用,因此将其放入循环中并继续调用它,直到数组中没有更多的零

编辑(Jörg W Mittag):通过使用解构bind和guard子句,您可以使其更加简洁易读:

ary.zip([nil] + ary.take(ary.length-1), ary.drop(1)).map {|prv, cur, nxt|
  next prv unless prv.nil?
  next cur unless cur.nil?
  nxt
}
如果以这种方式重构,很容易看出块所做的一切都是在前一个当前下一个三元组中查找第一个非
nil
元素,可以更简洁地表示为:

ary.zip([nil] + ary.take(ary.length-1), ary.drop(1)).map {|triple|
  triple.find {|el| !el.nil? }
}

反过来,通过使用
数组#compact

可以进一步简化这一点。我的第一个想法是这样的,现在它适用于任意零序列的一般情况

t = nil
p = lambda do |e|
  if e.nil?
    e,t = t,e
  else
    t = e
  end
  e
end
r = a
while r.any? && (r.include? nil)
  t = nil; r = r.map(&p)
  t = nil; r = r.reverse.map(&p).reverse
end
但我更喜欢这个。(API是
arrayObj.merge\u all


我的第一个想法是这样的,现在修正了任意零序列的一般情况

t = nil
p = lambda do |e|
  if e.nil?
    e,t = t,e
  else
    t = e
  end
  e
end
r = a
while r.any? && (r.include? nil)
  t = nil; r = r.map(&p)
  t = nil; r = r.reverse.map(&p).reverse
end
但我更喜欢这个。(API是
arrayObj.merge\u all


您并没有真正提到使用数组的目的,但是用0替换nil可能更有意义,因为如果您想取平均值或其他值,它不会影响结果

[1,2,3,nil,5].map { |el| el ? el : 0 }

您并没有真正提到使用数组的目的,但是用0替换nil可能更有意义,因为如果您想取平均值或其他值,它不会影响结果

[1,2,3,nil,5].map { |el| el ? el : 0 }

这是我的解决办法。它将适用于数组中任意数量的
nil
s,如果数组中的每个元素都是
nil
,它将正常失败。如果数组中的
nil
前有一个非nil,后有一个非nil,它将随机选择before或before

初始和安全检查:

arr = [1,nil,nil,4,5]
if arr.nitems == 0
  raise "all nil! don't know what to do!"
else
解决方案的核心:

  while (arr.index(nil))
    arr.each_index do |i|
      arr[i] = [arr[i-1], arr[i+1]] [rand 2]   if arr[i].nil?
    end
  end
总结:

end
arr  #print result for review
这已经用您的每个示例实例(开始时为nil,结束时为nil,中间为double nil)进行了测试,应该适用于任何数组大小

注意事项:

  • 数组中第一个元素“之前”的项是最后一个元素

    • 这是我的解决方案。它将适用于数组中任意数量的
      nil
      s,如果数组中的每个元素都是
      nil
      ,它将正常失败。如果数组中的
      nil
      前有一个非nil,后有一个非nil,它将随机选择before或before

      初始和安全检查:

      arr = [1,nil,nil,4,5]
      if arr.nitems == 0
        raise "all nil! don't know what to do!"
      else
      
      解决方案的核心:

        while (arr.index(nil))
          arr.each_index do |i|
            arr[i] = [arr[i-1], arr[i+1]] [rand 2]   if arr[i].nil?
          end
        end
      
      总结:

      end
      arr  #print result for review
      
      这已经用您的每个示例实例(开始时为nil,结束时为nil,中间为double nil)进行了测试,应该适用于任何数组大小

      注意事项:

      • 数组中第一个元素“之前”的项是最后一个元素

      这是DigitalRoss解决方案的直接副本,但处理连续两个以上零的边缘情况。我相信DigitalRoss将能够更优雅地完成这项工作,并且没有非idomatic ruby while循环,但这适用于所有测试案例

      def un_nil(arr)
        return arr if arr.compact.size == 0 || ! arr.include?(nil)
        while arr.include?(nil)
          t = nil
          p = lambda do |e|
            if e.nil?
              e,t = t,e
            else
              t = e
            end
            e
          end
          t = nil; r = arr.map(&p)
          t = nil; r = r.reverse.map(&p).reverse
          arr = r
        end
        arr
      end
      
      
      tests = [
      [1,2,3,4,5],  
      [1,2,3,nil,5],  
      [nil,2,3,4,5], 
      [1,nil,nil,4,5],
      [1,nil,nil,nil,5],
      [nil,nil,3,nil,nil],
      [nil,nil,nil,nil,nil]
      ]
      
      tests.each {|a| puts "Array #{a.inspect} became #{un_nil(a).inspect}" }
      
      这将产生以下输出

      Array [1, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, 2, 3, nil, 5] became [1, 2, 3, 3, 5]
      Array [nil, 2, 3, 4, 5] became [2, 2, 3, 4, 5]
      Array [1, nil, nil, 4, 5] became [1, 1, 4, 4, 5]
      Array [1, nil, nil, nil, 5] became [1, 1, 1, 5, 5]
      Array [nil, nil, 3, nil, nil] became [3, 3, 3, 3, 3]
      Array [nil, nil, nil, nil, nil] became [nil, nil, nil, nil, nil]
      

      这是DigitalRoss解决方案的直接副本,但可处理连续两个以上零的边缘情况。我相信DigitalRoss将能够更优雅地完成这项工作,并且没有非idomatic ruby while循环,但这适用于所有测试案例

      def un_nil(arr)
        return arr if arr.compact.size == 0 || ! arr.include?(nil)
        while arr.include?(nil)
          t = nil
          p = lambda do |e|
            if e.nil?
              e,t = t,e
            else
              t = e
            end
            e
          end
          t = nil; r = arr.map(&p)
          t = nil; r = r.reverse.map(&p).reverse
          arr = r
        end
        arr
      end
      
      
      tests = [
      [1,2,3,4,5],  
      [1,2,3,nil,5],  
      [nil,2,3,4,5], 
      [1,nil,nil,4,5],
      [1,nil,nil,nil,5],
      [nil,nil,3,nil,nil],
      [nil,nil,nil,nil,nil]
      ]
      
      tests.each {|a| puts "Array #{a.inspect} became #{un_nil(a).inspect}" }
      
      这将产生以下输出

      Array [1, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, 2, 3, nil, 5] became [1, 2, 3, 3, 5]
      Array [nil, 2, 3, 4, 5] became [2, 2, 3, 4, 5]
      Array [1, nil, nil, 4, 5] became [1, 1, 4, 4, 5]
      Array [1, nil, nil, nil, 5] became [1, 1, 1, 5, 5]
      Array [nil, nil, 3, nil, nil] became [3, 3, 3, 3, 3]
      Array [nil, nil, nil, nil, nil] became [nil, nil, nil, nil, nil]
      

      这完全取决于您以后想对数据做什么。对你来说,输入平均值可能是有意义的,但如果你有相对较小的数组,并且为了一点乐趣,你可以使用如下方法:

      require 'classifier'
      $c = Classifier::Bayes.new
      
      perm = [1, 2, 3, 4, 5].permutation(5)
      perm.each { |v| $c.add_category v * "," } 
      perm.each { |v| $c.train v*"," , v*","  } 
      
      def guess(arr)
         s = $c.classify(arr*",")
         a = s.split(',').map{|s| s.to_i}
      end
      
      tests = [
      [1,2,3,4,5],  
      [1,2,3,nil,5],  
      [nil,2,3,4,5], 
      [1,nil,nil,4,5],
      [1,nil,nil,nil,5],
      [nil,nil,3,nil,nil],
      [nil,nil,nil,nil,nil]
      ]
      
      tests.each { |t| puts "Array #{t.inspect} became #{guess(t).inspect}" }
      
      Array [1, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, 2, 3, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, nil, 3, nil, nil] became [1, 2, 3, 4, 5]
      Array [nil, nil, nil, nil, nil] became [1, 2, 3, 4, 5]
      
      输出如下所示:

      require 'classifier'
      $c = Classifier::Bayes.new
      
      perm = [1, 2, 3, 4, 5].permutation(5)
      perm.each { |v| $c.add_category v * "," } 
      perm.each { |v| $c.train v*"," , v*","  } 
      
      def guess(arr)
         s = $c.classify(arr*",")
         a = s.split(',').map{|s| s.to_i}
      end
      
      tests = [
      [1,2,3,4,5],  
      [1,2,3,nil,5],  
      [nil,2,3,4,5], 
      [1,nil,nil,4,5],
      [1,nil,nil,nil,5],
      [nil,nil,3,nil,nil],
      [nil,nil,nil,nil,nil]
      ]
      
      tests.each { |t| puts "Array #{t.inspect} became #{guess(t).inspect}" }
      
      Array [1, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, 2, 3, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, nil, 3, nil, nil] became [1, 2, 3, 4, 5]
      Array [nil, nil, nil, nil, nil] became [1, 2, 3, 4, 5]
      

      这完全取决于您以后想对数据做什么。对你来说,输入平均值可能是有意义的,但如果你有相对较小的数组,并且为了一点乐趣,你可以使用如下方法:

      require 'classifier'
      $c = Classifier::Bayes.new
      
      perm = [1, 2, 3, 4, 5].permutation(5)
      perm.each { |v| $c.add_category v * "," } 
      perm.each { |v| $c.train v*"," , v*","  } 
      
      def guess(arr)
         s = $c.classify(arr*",")
         a = s.split(',').map{|s| s.to_i}
      end
      
      tests = [
      [1,2,3,4,5],  
      [1,2,3,nil,5],  
      [nil,2,3,4,5], 
      [1,nil,nil,4,5],
      [1,nil,nil,nil,5],
      [nil,nil,3,nil,nil],
      [nil,nil,nil,nil,nil]
      ]
      
      tests.each { |t| puts "Array #{t.inspect} became #{guess(t).inspect}" }
      
      Array [1, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, 2, 3, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, nil, 3, nil, nil] became [1, 2, 3, 4, 5]
      Array [nil, nil, nil, nil, nil] became [1, 2, 3, 4, 5]
      
      输出如下所示:

      require 'classifier'
      $c = Classifier::Bayes.new
      
      perm = [1, 2, 3, 4, 5].permutation(5)
      perm.each { |v| $c.add_category v * "," } 
      perm.each { |v| $c.train v*"," , v*","  } 
      
      def guess(arr)
         s = $c.classify(arr*",")
         a = s.split(',').map{|s| s.to_i}
      end
      
      tests = [
      [1,2,3,4,5],  
      [1,2,3,nil,5],  
      [nil,2,3,4,5], 
      [1,nil,nil,4,5],
      [1,nil,nil,nil,5],
      [nil,nil,3,nil,nil],
      [nil,nil,nil,nil,nil]
      ]
      
      tests.each { |t| puts "Array #{t.inspect} became #{guess(t).inspect}" }
      
      Array [1, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, 2, 3, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, 2, 3, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, 4, 5] became [1, 2, 3, 4, 5]
      Array [1, nil, nil, nil, 5] became [1, 2, 3, 4, 5]
      Array [nil, nil, 3, nil, nil] became [1, 2, 3, 4, 5]
      Array [nil, nil, nil, nil, nil] became [1, 2, 3, 4, 5]
      
      这是一种变体:

      要求“测试/单元”
      类TestArrayCompletion
      这是一种:

      要求“测试/单元”
      类TestArrayCompletion
      我觉得传播最后一个非nil值就不那么令人惊讶了