2012-10-29 30 views
7

Ho una matrice a due elementi di oggetti ActiveRecord, slots_to_import. Questi oggetti hanno colonne begin_at e quindi attributi. Stavo cercando di ottenere oggetti con valori unici begin_at. Ahimè, slots_to_import.uniq_by(&:begin_at) non ha funzionato. Ma i valori begin_at sono uguali per i due oggetti:Striatura di 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] 

Qualche altro controllo in giro:

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

ho pensato che forse uniq stava controllando se fossero lo stesso oggetto (dal momento che non erano). Ma no, alcuni noodling nella mia console rotaie mi ha mostrato che non fa uso di un controllo oggetto 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] 

sto usando Rubino 1.8.7p358 e ActiveSupport 3.2.0. A proposito, posso risolvere il mio problema semplicemente aggiungendo un to_datetime, ma sono davvero curioso del perché questo non funziona senza una conversione.

+4

Hai provato a confrontare i risultati di 'x.hash' e' y.hash'? – hammar

+0

@hammar: È un'idea interessante vedere come 'uniq_by' è basato su Hash. –

+0

@hammar 'x.hash' e' y.hash' sono uguali! - '(rdb: 1) p slots_to_import.first.begin_at.hash == slots_to_import.last.begin_at.hash => true' – ehsanul

risposta

0

Diversi microsecondi è la mia ipotesi. 2 oggetti possono mostrare la stessa stringa di controllo ma non essere uguali.

+0

Hai ragione riguardo alla stringa inspect, ma hai sbagliato sui microsecondi. Noterai che controllo con il metodo 'usec' nella mia domanda. Citazione: '(rdb: 1) p [slots_to_import.last.begin_at.usec, slots_to_import.last.begin_at.usec] .uniq => [0]' – ehsanul

+0

Inoltre, non penso due volte/ora con diversi microsecondi sarà == tra loro: '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 

Il test di uguaglianza di Ruby si basa sul valore, non sul riferimento. Se si desidera confrontare se fanno riferimento allo stesso oggetto, si dovrebbe confrontare o.object_id

+0

Mi interessa il valore, non il riferimento. Nel tuo snippet, i valori sono uguali e "uniq" lo riflette. Nel mio, i valori sono uguali, ma l'uniq non riflette questo. – ehsanul

1

ho pensato si stava lavorando con semplici Time oggetti, così ho iniziato, cercando in time.c dalla sorgente piattaforma di Rubino (1.9.3). Se fossero di Ruby 1.9.3 Time oggetti, si potrebbe provare:

[x.to_r, y.to_r] 

Ora so che stai lavorando con ActiveSupport::TimeWithZone oggetti. (Come un suggerimento, sarebbe bene ricordare le informazioni chiave come questo la prossima volta che si posta una domanda.) Qui è il corpo di ActiveSupport::TimeWithZone#eql?:

def eql?(other) 
    utc == other 
end 

Ed ecco la funzione hash:

alias :hash, :to_i 

Quindi il passo successivo è per te per mostrare quello che ottieni da [x.utc, y.utc, x.to_i, y.to_i, x.utc.class, y.utc.class].

+0

È per ruby ​​1.8.7p358?Ricevo 'NoMethodError: metodo non definito \' to_r'' se faccio 'Time.now.to_r'. Inoltre, questi particolari oggetti 'ActiveSupport :: TimeWithZone' sono supportati da oggetti' DateTime', a cui manca anche il metodo 'to_r'. – ehsanul

+0

Stavo guardando il sorgente per Ruby 1.9.3. Se avrò tempo potrei dare un'occhiata alla sorgente di Ruby 1.8 ... nel frattempo, invece, prova a "to_f". –

+0

Grazie! Ho già fatto un controllo 'to_f' e l'ho incluso nella domanda originale - sono uguali anche a questo riguardo. – ehsanul

Problemi correlati