Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby array - how can I make values persist over nil values

Tags:

arrays

ruby

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?

like image 367
AJFaraday Avatar asked Jan 18 '15 15:01

AJFaraday


3 Answers

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

like image 98
tmnsun Avatar answered Nov 15 '22 06:11

tmnsun


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]
like image 23
sawa Avatar answered Nov 15 '22 06:11

sawa


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).

like image 30
Cary Swoveland Avatar answered Nov 15 '22 06:11

Cary Swoveland