2012-07-31 24 views
7

Estoy tratando de agrupar una matriz de enteros en un hash en función de dónde caen los valores individuales en un rango. Básicamente, quiero convertir una matriz a un histograma de ancho fijo.Ruby Array to Histogram: cómo agrupar números por rango?

Ejemplo:

values = [1,3,4,4,4,4,4,10,12,15,18] 
bin_width = 3 

necesito grupo los valores de la matriz en un historgram a base de gama por donde caen en una amplia cubo 3-unidad, así:

{'0..2'=>[1,3],'3..5'=>[4,4,4,4,4],'6..8'=>[],'9..11'=>[10].... 

Es hay una solución simple de una línea (tal vez algo como values.group_by{|x| #range calc}) que funcionaría aquí?

+1

preguntas: 1) Creo que debería estar en 3 3..5. 2) ¿por qué usar cadenas como teclas en lugar de rangos reales ?, 3) ¿necesita también los rangos vacíos? – tokland

+3

no debería haber obsesión por escribir frases ingeniosas. Esforzarse por soluciones que solo involucren expresiones (eso es, usar un enfoque funcional) sí, temer las asignaciones para guardar un par de líneas, no. – tokland

Respuesta

10
values = [1, 7, 2, 8, 2] 
values.group_by { |x| x/3 }.map { |k, vs| [(3*k..3*k+2), vs] }.to_h 
#=> {0..2=>[1, 2, 2], 6..8=>[7, 8]} 

Si realmente necesita los rangos vacíos, no creo que sea posible una línea limpia. Pero esto debe hacer:

grouped = values.group_by { |x| x/3 } 
min, max = grouped.keys.minmax 
(min..max).map { |n| [(3*n..3*n+2), grouped.fetch(n, [])] }.to_h 
#=> {0..2=>[1, 2, 2], 3..5=>[], 6..8=>[7, 8]} 
+0

Ja, solo quería sugerir algo que no requiere Facetas y luego actualizaste tu publicación. –

+1

@Michael, sí, lo siento, de hecho, mi fragmento de facetas era completamente incorrecto, map_by no es útil aquí, necesitamos procesar las claves, no los valores. Así es como lo escribirías? – tokland

4

me ocurrió una solución bastante ineficiente, pero bastante claro:

ranges = 0.step(values.max, bin_width).each_cons(2).map { |s, e| Range.new(s, e, true) } 
values.group_by { |v| ranges.find { |r| r.cover? v } } 
+0

Gracias por la versión más general que funciona tanto con contenedores de 3 unidades y se puede adaptar a casos más arbitrarios. Justo lo que necesitaba. – slothbear