2012-10-29 18 views
7

Tôi có một mảng hai phần tử của đối tượng ActiveRecord, slots_to_import. Các đối tượng này có các cột begin_at và do đó là các thuộc tính. Tôi đã cố gắng để có được các đối tượng có giá trị begin_at duy nhất. Than ôi, slots_to_import.uniq_by(&:begin_at) không hoạt động. Nhưng begin_at giá trị đều bình đẳng cho hai đối tượng:Tính lạ lùng của Ruby: x == y && [x, y] .uniq == [x, y]

(rdb:1) p slots_to_import.first.begin_at == slots_to_import.last.begin_at 
true 
(rdb:1) p slots_to_import.uniq_by(&:begin_at).map(&:begin_at) 
[Mon, 26 Nov 2012 19:00:00 UTC +00:00, Mon, 26 Nov 2012 19:00:00 UTC +00:00] 
(rdb:1) p [slots_to_import.first.begin_at, slots_to_import.last.begin_at].uniq 
[Mon, 26 Nov 2012 19:00:00 UTC +00:00, Mon, 26 Nov 2012 19:00:00 UTC +00:00] 

Một số chi tiết kiểm tra xung quanh:

(rdb:1) p [slots_to_import.first.begin_at.to_datetime, slots_to_import.last.begin_at.to_datetime].uniq 
[Mon, 26 Nov 2012 19:00:00 +0000] 
(rdb:1) p [slots_to_import.first.begin_at.usec, slots_to_import.last.begin_at.usec].uniq 
[0] 
(rdb:1) p [slots_to_import.first.begin_at.to_f, slots_to_import.last.begin_at.to_f].uniq 
[1353956400.0] 
(rdb:1) p [slots_to_import.first.begin_at.utc, slots_to_import.last.begin_at.utc].uniq 
[Mon, 26 Nov 2012 19:00:00 +0000] 
(rdb:1) p [slots_to_import.first.begin_at, slots_to_import.last.begin_at].uniq 
[Mon, 26 Nov 2012 19:00:00 UTC +00:00, Mon, 26 Nov 2012 19:00:00 UTC +00:00] 

Tôi nghĩ có lẽ uniq đã được kiểm tra xem họ đã cùng một đối tượng (vì họ không). Nhưng không, một số noodling trong giao diện điều khiển đường ray của tôi cho thấy tôi rằng nó không sử dụng một id đối tượng kiểm tra:

1.8.7 :111 > x = Time.zone.parse("Mon, 29 Oct 2012 19:29:17 UTC +00:00") 
=> Mon, 29 Oct 2012 19:29:17 UTC +00:00 
1.8.7 :112 > y = Time.zone.parse("Mon, 29 Oct 2012 19:29:17 UTC +00:00") 
=> Mon, 29 Oct 2012 19:29:17 UTC +00:00 
1.8.7 :113 > x == y 
=> true 
1.8.7 :114 > [x, y].uniq 
=> [Mon, 29 Oct 2012 19:29:17 UTC +00:00] 

Tôi đang sử dụng Ruby 1.8.7p358 và ActiveSupport 3.2.0. BTW, tôi có thể giải quyết vấn đề của riêng mình bằng cách chỉ cần thêm một số to_datetime, nhưng tôi thực sự tò mò tại sao điều này không hoạt động nếu không có chuyển đổi.

+4

Bạn đã thử so sánh kết quả của 'x.hash' và' y.hash'? – hammar

+0

@hammar: Đó là một ý tưởng thú vị khi thấy 'uniq_by' là Hash dựa. –

+0

@hammar 'x.hash' và' y.hash' cũng bằng nhau! - '(rdb: 1) p slots_to_import.first.begin_at.hash == slots_to_import.last.begin_at.hash => true' – ehsanul

Trả lời

0

Các micro giây khác nhau là dự đoán của tôi. 2 đối tượng có thể hiển thị cùng chuỗi kiểm tra nhưng không bằng nhau.

+0

Bạn đang đúng về chuỗi kiểm tra, nhưng sai về micro giây. Bạn sẽ lưu ý rằng tôi kiểm tra với phương thức 'usec' trong câu hỏi của tôi. Trích: '(rdb: 1) p [slots_to_import.first.begin_at.usec, slots_to_import.last.begin_at.usec] .uniq => [0]' – ehsanul

+0

Ngoài ra, tôi không nghĩ hai thời gian/lần với các micro giây khác nhau sẽ được == với nhau: '1.8.7: 006> Time.now == Time.now => false' – ehsanul

0
irb(main):017:0> x = 'a' 
=> "a" 
irb(main):018:0> y = 'a' 
=> "a" 
irb(main):019:0> x == y 
=> true 
irb(main):020:0> [x,y].uniq 
=> ["a"] 
irb(main):021:0> x.object_id == y.object_id 
=> false 
irb(main):024:0> x.hash == y.hash 
=> true 

Kiểm tra bình đẳng Ruby dựa trên giá trị chứ không phải tham chiếu. Nếu bạn muốn so sánh nếu họ đang tham chiếu đến cùng một đối tượng, bạn nên so sánh o.object_id

+0

Tôi quan tâm đến giá trị, không tham chiếu. Trong đoạn mã của bạn, các giá trị bằng nhau và 'uniq' phản ánh điều đó. Trong tôi, các giá trị bằng nhau, nhưng uniq không phản ánh điều đó. – ehsanul

1

tôi nghĩ bạn đang làm việc với đồng bằng Time đối tượng, vì vậy tôi bắt đầu bằng cách nhìn vào time.c từ nguồn nền tảng Ruby (1.9.3). Nếu họ của Ruby 1.9.3 Time đối tượng, bạn có thể thử:

[x.to_r, y.to_r] 

Bây giờ tôi biết bạn đang làm việc với ActiveSupport::TimeWithZone đối tượng. (Như một gợi ý, nó sẽ là tốt để đề cập đến thông tin quan trọng như thời gian tiếp theo này, bạn gửi một câu hỏi.) Đây là cơ quan của ActiveSupport::TimeWithZone#eql?:

def eql?(other) 
    utc == other 
end 

Và đây là các hàm băm:

alias :hash, :to_i 

Vì vậy, bước tiếp theo là để bạn hiển thị những gì bạn nhận được từ [x.utc, y.utc, x.to_i, y.to_i, x.utc.class, y.utc.class].

+0

Đây có phải là ruby ​​1.8.7p358 không?Tôi nhận được 'NoMethodError: phương thức undefined \' to_r'' nếu tôi làm 'Time.now.to_r'. Ngoài ra, các đối tượng 'ActiveSupport :: TimeWithZone' cụ thể này được các đối tượng' DateTime' hỗ trợ, cũng thiếu phương thức 'to_r'. – ehsanul

+0

Tôi đã xem mã nguồn của Ruby 1.9.3. Nếu tôi có thời gian tôi có thể nhìn vào nguồn Ruby 1.8 ... trong khi chờ đợi hãy thử 'to_f'. –

+0

Cảm ơn! Tôi đã làm một kiểm tra 'to_f' và bao gồm trong câu hỏi ban đầu - họ cũng bình đẳng về vấn đề đó. – ehsanul