2012-06-29 33 views
7

giả sử tôi có các mảng sau:của Ruby đếm ngược phát hiện

views = [ 
    { :user_id => 1, :viewed_at => '2012-06-29 17:03:28 -0400' }, 
    { :user_id => 1, :viewed_at => '2012-06-29 17:04:28 -0400' }, 
    { :user_id => 2, :viewed_at => '2012-06-29 17:05:28 -0400' }, 
    { :user_id => 3, :viewed_at => '2012-06-29 17:06:28 -0400' }, 
    { :user_id => 1, :viewed_at => '2012-06-29 17:07:28 -0400' }, 
    { :user_id => 1, :viewed_at => '2012-06-29 17:08:28 -0400' }, 
    { :user_id => 3, :viewed_at => '2012-06-29 17:09:28 -0400' }, 
    { :user_id => 3, :viewed_at => '2012-06-29 17:16:28 -0400' }, 
    { :user_id => 3, :viewed_at => '2012-06-29 17:26:28 -0400' }, 
    { :user_id => 3, :viewed_at => '2012-06-29 17:36:28 -0400' }, 
    { :user_id => 1, :viewed_at => '2012-06-29 17:47:28 -0400' }, 
    { :user_id => 2, :viewed_at => '2012-06-29 17:57:28 -0400' }, 
    { :user_id => 3, :viewed_at => '2012-06-29 17:67:28 -0400' }, 
    { :user_id => 1, :viewed_at => '2012-06-29 17:77:28 -0400' } 
] 

giả sử mảng được sắp xếp theo viewed_at

Nếu tôi muốn lấy lại băm xem cuối cùng trong xem mảng cho cụ thể user_id, tôi có thể làm như sau:

views.reverse.detect { |view| view[:user_id] == 1 } 

trong đó phát hiện sẽ trả về mục đầu tiên trong một liệt kê trong đó khối đánh giá là đúng.

Câu hỏi của tôi là: Tôi giả sử có O(n) chi phí cho phương thức đảo ngược, vậy làm thế nào tôi có thể phát hiện ngược lại mà không phải đảo ngược mảng? Hoặc là phương pháp đảo ngược không phải là O(n)?

+6

bạn có thực sự có '17: 77' như một thời điểm? –

+0

Khi bạn kết chuỗi các phương thức, bạn luôn muốn nối chuỗi các điều tra viên. Chuỗi điều tra chỉ lặp lại đối tượng một lần và là O (n). Ví dụ phổ biến nhất là "hello" .each_char.map {| x | x.succ} ' – texasbruce

+0

@texasbruce: điều đó sẽ hoàn toàn đúng với Ruby 2.0, nơi mà tất cả các loại hoạt động lười biếng sẽ có thể thực hiện được (bây giờ rất nhiều hoạt động trở lại mảng, không phải là điều tra viên) – tokland

Trả lời

18

Phương pháp Array#reverse là O (n) theo thời gian và không gian. Vì bạn không cần toàn bộ mảng bị đảo ngược, bạn có thể sử dụng Array#reverse_each, đó sẽ là O (1) trong không gian. Trong thực tế, điều đó chỉ phù hợp với các mảng thực sự lớn.

views.reverse_each.detect { |view| view[:user_id] == 1 } 
#=> {:user_id=>1, :viewed_at=>"2012-06-29 17:77:28 -0400"} 
+0

điều này rất thú vị. Tôi thấy phương pháp ngược lại trong mỗi tài liệu Ruby 1.9.3 Enumerable, nhưng tên của nó ngụ ý rằng nó lặp qua từng đối tượng trong một số đếm. Tôi thấy bằng ví dụ của bạn rằng nó không (có khả năng nó có thể). Bạn có thể giải thích sự khác biệt giữa thời gian một không gian trong bối cảnh này không. Cảm ơn câu trả lời chu đáo của bạn! –

+2

"tên của nó ngụ ý rằng nó lặp qua từng đối tượng trong một số đếm". Phương thức 'each' trong Ruby luôn lười, chúng lặp lại toàn bộ số đếm nếu được yêu cầu, nhưng ở đây nó sẽ dừng lại khi' detect' ngừng hỏi nhiều giá trị hơn. "Bạn có nhớ giải thích sự khác biệt giữa thời gian một không gian trong bối cảnh này". Sử dụng reverse_each: time) bạn có khả năng cần phải đi qua toàn bộ đầu vào để tìm kết quả phù hợp, vì vậy nó tuyến tính O (n) trong trường hợp xấu nhất, không gian) bạn chỉ cần tích lũy phần tử hiện tại đang được kiểm tra, đó là O (1). Ví dụ bằng Python: http://wiki.python.org/moin/TimeComplexity – tokland

+0

cảm ơn bạn rất nhiều! –

1

Điều này sẽ lấy chỉ mục từ đối tượng cuối cùng mà khối đó là đúng (hoặc không nếu không khớp).

views.rindex{|view| view[:user_id] == 1} 

Sau benchmarking @toklands reverse_each là (đáng ngạc nhiên đối với tôi) nhanh hơn rất nhiều:

require 'benchmark' 
ar = Array.new(100){rand(100)} 
target = rand(100) 

Benchmark.bm(15) do |x| 
    x.report('reverse_each'){1000.times{ar.reverse_each.detect(target)}} 
    x.report('rindex'){1000.times{ar.rindex(target)}} 
end 


#      user  system  total  real 
#reverse_each  0.000000 0.000000 0.000000 ( 0.002981) 
#rindex   0.020000 0.000000 0.020000 ( 0.012078) 
+0

thực sự đáng ngạc nhiên, về khái niệm nó là cùng một hoạt động, thời gian nên rất giống nhau. – tokland