I'm working with an array of midi pitches, which looks like this...
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
]
In this case, the pitch is still 60 on indexes 1, 2 and 3.
Following index 4, the pitch is still 67.
How can I write a method to identify the previous non-nil value?
The only way I can currently think to do it looks a little clumsy:
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
The expected output is in the format:
pitch_at_step(pitches, 0) # 60
pitch_at_step(pitches, 2) # 60
pitch_at_step(pitches, 4) # 67
pitch_at_step(pitches, 8) # 67
Is this the best solution? is there a tidier and/or more efficient way?
If array is not big you can use something like this:
pitches[0..index].compact.last
This seems tidier, but it's not as good as your for big arrays of data
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]
Here's a simple way to construct the converted array:
last = pitches.first
pitches[1..-1].map { |i| curr = i || last; last = curr; curr }
.unshift(pitches.first)
#=> [60, 60, 60, 60, 67,... 67]
The OP did not say whether the first element of pitches
is always non-nil. Suppose:
pitches = [nil, nil, 61, nil, nil, 60, nil]
The above method would return:
[nil, nil, 61, 61, 61, 60, 60]
which is what we would want. Some of the other answers stumble when pitches[step] = nil
and pitches[i] = nil
for all i < step
(step
being the index of the given element of pitches
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With