Perché Hash#partition non restituisce due Hash?

Ciao:

h = {'a' => 1, 'b' => 2, 'c' => 3}
selected = h.select {|key, val| key < 'b' or val > 2}

e giustamente:

selected #=> {"a"=>1, "c"=>3}

Ora, sempre nella classe Hash, il metodo partition dovrebbe avere un
comportamento simile, e restituire due Hash:

selected, discarded = h.partition {|key, val| key < 'b' or val > 2}

invece:

selected  #=> [["a", 1], ["c", 3]]
discarded #=> [["b", 2]]

quando mi sembrerebbe più pulito e coerente ottenere:

selected  #=> {"a" => 1, "c" => 3}
discarded #=> {"b" => 2}

So che è facilissimo convertire gli Array di sopra negli Hash di sotto,
ma mi chiedo il motivo di tale inconsistenza in core ruby. Cosa mi
sfugge?

Grazie,
Guido

P.S. faccio riferimento a ruby1.9, non so come si comporta 1.8.

Guido De Rosa wrote:

So che è facilissimo convertire gli Array di sopra negli Hash di sotto,
ma mi chiedo il motivo di tale inconsistenza in core ruby. Cosa mi
sfugge?

Non è un inconsistenza, è voluto:
dalle api:

enum.partition {| obj | block } => [ true_array, false_array ]

Returns two arrays, the first containing the elements of enum for which
the block evaluates to true, the second containing the rest.

(1…6).partition {|i| (i&1).zero?} #=> [[2, 4, 6], [1, 3, 5]]

ho dimenticato un pezzo :slight_smile:

è voluto in quanto partition non è un metodo di Hash ma di Enumerable,
quindi può applicarsi a qualsiasi collection, di conseguenza sarebbe
“incomprensibile” se restituisse valori differenti a seconda del tipo di
collection (almeno a mio parere :slight_smile: ).

Alessandro S. wrote:

ho dimenticato un pezzo :slight_smile:

è voluto in quanto partition non è un metodo di Hash ma di Enumerable,
quindi può applicarsi a qualsiasi collection, di conseguenza sarebbe
“incomprensibile” se restituisse valori differenti a seconda del tipo di
collection (almeno a mio parere :slight_smile: ).

Sì, ma allora lo stesso discorso si dovrebbe fare per select (che pure è
un metodo di Enumerable), e invece:

{'a' => 1, 'b' => 2, 'c' => 3}.select {|key, val| key < b or val > 2 

}

restituisce:

{"a"=>1, "c"=>3}

In base al ragionamento che hai appena fatto, sarebbe dovuto essere:

[["a", 1], ["c", 3]]

In effetti, stando alla documentazione, scopro solo ora che select si
comporta diversamente in ruby1.8 e ruby1.9 (e io uso 1.9).

http://ruby-doc.org/ruby-1.9/classes/Hash.html#M000401

Sembrerebbe che in ruby1.9 select sia stato riscritto per la classe
Hash, mentre in 1.8 resta il risultato della mera inclusione di
Enumerable.

Mi verrebbe da dire, a questo punto, che l’“inconsistenza” è solo di
ruby1.9. Nel senso che i due statement:

scelti, scartati = hash.partition {|key, val| #blocco di codice... }

e

scelti = hash.select {|key, val| #stesso blocco di codice... }

dovrebbero ragionevolmente assegnare alla variabile “scelti” lo stesso
valore (Hash o Array che sia).

E invece ciò è vero solo per 1.8, non per ruby 1.9 …

G.