2015-01-18 13 views
6

Tôi đang làm việc với một loạt các nốt midi, trông như thế này ...của Ruby mảng - làm thế nào tôi có thể làm cho các giá trị tồn tại qua con số không đánh giá cao

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 
] 

Trong trường hợp này, sân vẫn là 60 trên chỉ số 1, 2 và 3.

Tiếp theo chỉ số 4, sân vẫn là 67.

Làm thế nào tôi có thể viết một phương pháp để xác định các giá trị không bằng không trước đó?

Cách duy nhất tôi có thể nghĩ đến hiện để làm nó trông giống một chút vụng về:

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 

Sản lượng dự kiến ​​được ghi theo dạng:

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

Đây có phải là giải pháp tốt nhất? có cách nào hiệu quả hơn và/hoặc hiệu quả hơn không?

+0

Bạn có thể cũng cung cấp cho các đầu ra? Vì vậy, chúng tôi không cần phải chạy mã của bạn. –

+0

Nó phải là giá trị phi nil mới nhất, vì vậy 0: 60, 1: 60, 2: 60, 3: 60, 4: 67, 5: 67, 6: 67, v.v. – AJFaraday

Trả lời

4

Nếu mảng không phải là lớn, bạn có thể sử dụng một cái gì đó như thế này:

pitches[0..index].compact.last 

Điều này có vẻ ngăn nắp, nhưng nó không tốt như bạn đối với mảng lớn dữ liệu

+0

Điều này có vẻ tốt, vì nó xảy ra ứng dụng dựa trên các vòng lặp ngắn mà người dùng có thể sửa đổi. Tôi sẽ ngạc nhiên nếu họ vượt quá 64 bước. – AJFaraday

1

Để có được một giá trị:

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

Để tính toán tất cả các giá trị:

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

này cũng có thể đạt được với 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] 
2

Đây là một cách đơn giản để xây dựng các mảng chuyển đổi:

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

Các OP không nói cho dù các yếu tố đầu tiên của pitches luôn là phi nil . Giả sử:

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

Các phương pháp trên sẽ quay trở lại:

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

đó là những gì chúng tôi muốn. Một số câu trả lời khác vấp ngã khi pitches[step] = nilpitches[i] = nil cho tất cả i < step (step là chỉ mục của phần tử đã cho của pitches).

+0

Điểm tốt, câu trả lời đúng sẽ là mảng được đọc như là một mẫu lặp lại. Sân sẽ vẫn là giá trị cuối cùng được đặt thành. BAO GIỜ - có một mặt nạ bit xác định khi nào bắt đầu phát âm, thành viên đầu tiên sẽ ở cùng điểm với nốt được xác định đầu tiên, vì vậy không cần phải lo lắng về nils khi bắt đầu mảng – AJFaraday

2

Nếu bạn sắp có mảng lớn chủ yếu là nil, tại sao không sử dụng hàm băm thay vào đó, chỉ lưu trữ các giá trị không phải là số không? Và bạn nhìn vào các phím. (ở đây, một phiên bản chưa được tối ưu hóa)

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

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

Nếu hiệu suất là một vấn đề, bạn có thể theo dõi các phím được sắp xếp.

+0

Đây là một ý tưởng hay và cũng có thể giải quyết một vấn đề mà tôi có khả năng gặp phải với việc truyền dữ liệu qua JSON. Tuy nhiên nó có nghĩa là tôi sẽ phải thực hiện giải pháp này trong javascript trên máy khách. – AJFaraday

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] 
+0

Bản thân hạt nhân chỉ có sẵn từ phiên bản 2.2.0 trở đi. (Câu trả lời này chắc chắn đã dạy tôi một hoặc hai điều ...) –

+0

Hơi kém thanh lịch nhưng đối với những viên hồng ngọc trước đó, có vẻ như bạn có thể sử dụng 'slice_before {| x | x! = nil} ' –

0

Tôi nghĩ rằng đây là một cách tốt để làm điều đó trong Ruby:

pitches[0..index].reverse_each.find{|x|x} 
Các vấn đề liên quan