2012-10-29 16 views
7

Mam dwuelementową tablicę obiektów ActiveRecord, slots_to_import. Obiekty te mają kolumny begin_at, a więc atrybuty. Próbowałem uzyskać obiekty, które mają unikalne wartości begin_at. Niestety, slots_to_import.uniq_by(&:begin_at) nie działa. Ale wartości begin_at są równe dla obu obiektów:Dziwactwo rubowe: 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] 

Niektóre bardziej sprawdzanie wokół:

(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] 

myślałem chyba że uniq było sprawdzenie, czy były one ten sam przedmiot (ponieważ nie byli). Ale nie, niektóre noodling w moim konsoli szyn pokazał mi, że nie używa czek przedmiot id:

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] 

Używam Ruby 1.8.7p358 i ActiveSupport 3.2.0. BTW, mogę rozwiązać mój problem, po prostu dodając to_datetime, ale jestem naprawdę ciekawy, dlaczego to nie działa bez konwersji.

+4

Czy próbowałeś porównać wyniki 'x.hash' i' y.hash'? – hammar

+0

@hammar: To interesujący pomysł, ponieważ 'uniq_by' jest oparty na Hash. –

+0

@hammar 'x.hash' i' y.hash' są równe! - '(rdb: 1) p slots_to_import.first.begin_at.hash == slots_to_import.last.begin_at.hash => true' – ehsanul

Odpowiedz

0

Różne mikrosekundy to moje przypuszczenie. 2 obiekty mogą wyświetlać ten sam ciąg kontrolny, ale nie mogą być równe.

+0

Masz rację co do sprawdzanego ciągu znaków, ale jest on błędny w ciągu mikrosekund. Zauważysz, że sprawdzam za pomocą metody 'usec' w moim pytaniu. Cytuj: '(rdb: 1) p [slots_to_import.first.begin_at.usec, slots_to_import.last.begin_at.usec] .uniq => [0]' – ehsanul

+0

Ponadto, nie sądzę, dwa razy/czasy z różnymi mikrosekundami będzie == względem siebie: '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 

Test równości Rubiego oparty jest na wartości, a nie na referencji. Jeśli chcesz porównać, jeśli odwołują się do tego samego obiektu, należy porównać o.object_id

+0

Dbam o wartość, a nie referencję. W twoim fragmencie wartości są równe, a 'uniq' odzwierciedla to. W moim, wartości są równe, ale uniq tego nie odzwierciedla. – ehsanul

1

Myślałam, że pracuje z gładkimi Time obiektów, więc zacząłem patrząc na time.c od źródła platformy Ruby (1.9.3). Gdyby byli Ruby 1.9.3 Time obiekty, można spróbować:

[x.to_r, y.to_r] 

Teraz wiem, że pracujesz z ActiveSupport::TimeWithZone obiektów. (Jako sugestię, że byłoby dobrze, aby wymienić najważniejsze informacje jak ten następny raz piszesz pytanie.) Oto ciało ActiveSupport::TimeWithZone#eql?:

def eql?(other) 
    utc == other 
end 

I tu jest funkcja hash:

alias :hash, :to_i 

Następnym krokiem jest pokazanie, co można uzyskać z [x.utc, y.utc, x.to_i, y.to_i, x.utc.class, y.utc.class].

+0

Czy to dla rubinu 1.8.7p358?Otrzymuję 'NoMethodError: undefined method \' to_r'' jeśli zrobię 'Time.now.to_r'. Te obiekty 'ActiveSupport :: TimeWithZone' są również wspierane obiektami' DateTime', w których również brakuje metody 'to_r'. – ehsanul

+0

Szukałem źródła dla Ruby 1.9.3. Jeśli będę miał czas, mogę spojrzeć na źródło Ruby 1.8 ... w międzyczasie zamiast tego wypróbuj 'to_f'. –

+0

Dzięki! Zrobiłem już sprawdzanie 'to_f' i uwzględniłem to w pytaniu oryginalnym - są równe pod tym względem. – ehsanul

Powiązane problemy