2011-10-06 9 views
12

Tomemos este ejemplo:¿Cómo obtener solo un subconjunto de un hash ordenado en Ruby 1.9?

d = {"a" => 1, "b" => 2, "c" => 3, "d" => 4} 

Desde hashes están ordenados, puede ser que quiera obtener datos de a a b o desde c a d. El problema es que no puedo hacer d[0..1] o d[2..3].

pude hacer sin embargo:

irb > d.to_a[0..1] 
=> [["a", 1], ["b", 2]] 

... pero esto se siente desordenado y no quiero emitir mi hash para una operación como ésta.

¿Existe una solución más limpia para manejar esto?

# Holy Grail 
irb > d[0..1] 
=> {"a" => 1, "b" => 2} 

puedo ver cómo a mí mismo programar un procedimiento de este tipo, pero que podría haber algo nativa ya hecho que podría utilizar ...?

+0

Una gama también podría ser una clave hash válido, por lo que tendrá que utilizar un método personalizado para esto. No creo que no haya nada incorporado, por cierto. – tokland

Respuesta

7

Bien se podría hacer:

> a = {"a" => 1, "b" => 2, "c" => 3, "d" => 4} 
> a.slice(*a.keys[0..1]) 
=> {"a" => 1, "b" => 1} 

Al menos el hash no está echada, pero todavía no es muy elegante en mi opinión.

+0

Sería más elegante si simplemente lo envuelve en algún tipo de método conectado a Hash. – tadman

+0

Me gusta esta solución ^^ – marcgg

+0

esta es una forma de sonido, pero todavía tiene que obtener todas las claves del hash. Pero si la implementación no admite dividir el hash por el índice, es difícil encontrar algo mejor. – tokland

4

Si desea hacer comparaciones con la clave para seleccionar el subconjunto, puede usar Hash#select, también funciona en 1.8.7 pero devuelve una matriz de matrices en su lugar (según su ejemplo).

d.select {|k, v| k < 'c' } # => {"a"=>1, "b"=>2} 
d.select {|k, v| k < 'c' } # 1.8.7 => [["a", 1], ["b", 2]] 

También puede utilizar la extensión Hash de ActiveSupport que añade un slice method to Hash que también puede funcionar, siempre y cuando ya conoce las teclas que desee.

require 'active_support/core_ext/hash/slice' 
d.slice('a', 'b') # => {"a"=>1, "b"=>2} 
+0

En este caso, el OP querría un hash # slice_by_index con todas las opciones que Array # [] admite. – tokland

+0

Sí, la mayoría de las veces, usted conoce las claves que desea o cómo seleccionarlas en base a una comparación, pero las quiere en función del índice, que no es lo que contesté. Además de eso, mi respuesta es mala porque usa ActiveSupport donde solo se necesita Hash # values_at, como @DuoSRX mostró. –

+0

@BiHi En mi situación, quiero obtener las claves según su índice, no sus valores – marcgg

2

Probablemente hay una manera mejor de hacerlo, pero esto es una idea:

class Hash 
    def slice_by_index(a, b = nil) 
     k = if a.is_a?(Range) 
      keys[a] 
     elsif b.nil? 
      [keys[a]] 
     else 
      keys[a,b] 
     end 
     k.inject({}){|h, k| h[k] = self[k] ; h } 
    end 
end 

h = {"a" => 1, "b" => 2, "c" => 3, "d" => 4} 
p h.slice_by_index(1..3) #range 
p h.slice_by_index(2) #single element 
p h.slice_by_index(0,3) #start, lenght 
Cuestiones relacionadas