Ruby数组 - 如何使值保持在nil值之上

时间:2015-01-18 15:32:31

标签: ruby arrays

我正在使用一系列midi音高,看起来像这样......

pitches = [
  60, nil, nil, nil, 67, nil, nil, nil, 
  nil, nil, nil, nil, nil, nil, nil, nil, 
  nil, nil, nil, nil, nil, nil, nil, nil, 
  nil, nil, nil, nil, nil, nil, nil, nil
] 

在这种情况下,指数1,2和3的音高仍为60。

在指数4之后,音高仍然是67。

如何编写方法来识别先前的非零值?

我目前认为这样做的唯一方法看起来有点笨拙:

def pitch_at_step(pitches,step)
  if pitches.any?
    x = pitches[step]
    until x != nil
      index -= 1
      x = pitches[step]        
    end 
    x
  else
    nil
  end 
end

预期输出格式为:

pitch_at_step(pitches, 0) # 60
pitch_at_step(pitches, 2) # 60
pitch_at_step(pitches, 4) # 67
pitch_at_step(pitches, 8) # 67

这是最好的解决方案吗?是否有更整洁和/或更有效的方式?

7 个答案:

答案 0 :(得分:4)

如果数组不大,你可以使用这样的东西:

pitches[0..index].compact.last

这看起来更整洁,但它不如大数据阵列那么好

答案 1 :(得分:3)

pitches.slice_before(&:itself).flat_map{|a| a.fill(a.first)}
# => [60, 60, 60, 60, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 
#     67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67]

答案 2 :(得分:2)

这是构建转换数组的简单方法:

last = pitches.first
pitches[1..-1].map { |i| curr = i || last; last = curr; curr }
              .unshift(pitches.first)
  #=> [60, 60, 60, 60, 67,... 67] 

OP没有说明pitches的第一个元素是否总是非零。假设:

pitches = [nil, nil, 61, nil, nil, 60, nil]

上述方法将返回:

[nil, nil, 61, 61, 61, 60, 60] 

这就是我们想要的。对于所有pitches[step] = nil pitches[i] = nili < stepstep的给定元素的索引)pitches和{{1}}时,其他一些答案会发生绊倒。

答案 3 :(得分:2)

如果您要使用大多数nil的大型数组,为什么不使用哈希值,只存储非零值?你看着钥匙。 (这里是未经优化的版本)

pitches = {0 => 60, 4 => 67}

def find(idx)
  lower = pitches.keys.select { |i| i <= idx}
  return pitches[lower.sort.last]
end

如果性能有问题,您可以跟踪排序的密钥。

答案 4 :(得分:1)

获得一个值:

 value = index.downto(0){|i| pitches[i] and break pitches[i] }

计算所有值:

 values = (y = nil) || pitches.map{|x| x ? y = x : y }

答案 5 :(得分:1)

这也可以通过Enumerable#chunk

来实现
tmp = nil
pitches.chunk {|el| tmp = el unless el.nil?; tmp }.
  map {|val, ar| [val] * ar.size }.flatten
# => [60, 60, 60, 60, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 
#     67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67]

答案 6 :(得分:0)

我认为这是在Ruby中实现它的好方法:

pitches[0..index].reverse_each.find{|x|x}