2010-10-18 9 views
10

Digamos que tengo la siguiente matriz:Proporcionar un proc a un método como un bloque

arr = [[5, 1], [2, 7]] 

y quiero encontrar el elemento mínimo, comparando el segundo elemento de los elementos. El elemento mínimo será [5, 1] ya que 1 es menor que 7. Puedo usar el siguiente código:

arr.min {|a,b| a[1] <=> b[1]} 

Para calcular el máximo, puedo hacer lo mismo:

arr.max {|a,b| a[1] <=> b[1]} 

Eso da [2, 7].

Uso el mismo bloque todo el tiempo. Me gustaría tener ese bloque en alguna parte y proporcionarlo a la función min/max. Esperaba algo como:

blo = lambda {|a,b| a[1] <=> b[1]} 
arr.min blo 

funcionaría, pero no fue así. ¿Alguna idea sobre cómo puedo hacer esto?

Respuesta

23

utilizar el operador & para convertir un objeto Proc en un bloque.

arr.min &blo 
+2

El único que lee la pregunta con cuidado. – Nakilon

+0

Esto es exactamente lo que estaba buscando. Muchas gracias por la respuesta! –

+0

@ Cristóbal quizás debería "aceptar" la respuesta con la que está satisfecho. Indica a otros usuarios que esta pregunta ha sido respondida y aceptada. –

2

¿qué tal esto?

=> [[5, 4], [9, 5], [2, 7]] 
>> arr.sort!{|x,y| x[1]<=>y[1] } 
=> [[5, 4], [9, 5], [2, 7]] 
>> min,max=arr[0],arr[-1] 
=> [[5, 4], [2, 7]] 
13

@ respuesta de sepp2k es el más general, pero en su caso concreto, yo sólo uso

arr.min_by(&:last) 
arr.max_by(&:last) 

ya que es mucho más evidente que todas esas llaves y corchetes y índices de matriz flotando alrededor.

+0

Éste también funciona;) –

+0

Eso es lo que estaba buscando, por lo que puede hacer 'line_items.max_by (&: quantity)' por ejemplo. Muchas gracias – Dorian

1

una solución más general a problemas como esto es para evitar matrices anidadas por completo y utilizar una clase en su lugar. A continuación, puede definir el < => operador para esa clase, que le da acceso a todas las funciones en el mixin Comparable (http://ruby-doc.org/core/classes/Comparable.html) le da la <, < = , ==,> =, y> operadores y el método 'entre?'

Esto es sólo un ejemplo, en la vida real que usaría clases que describen lo que la tienda:

class Duo 

    include Comparable 

    def initialize(a, b) 
     @a = a 
     @b = b 
    end 

    def <=>(rhs) 
     @b <=> rhs.b 
    end 

end 

Si usted tiene una serie de Duo oponerse a continuación, puede utilizar el mínimo, máximo, y funciones de clasificación sin tener que definir el operador de comparación. Así que ...

@a = Duo.new(1, 10) 
@b = Duo.new(2, 5) 
@c = Duo.new(3, 1) 

[ @a, @b, @c ].sort 

sería devolver la matriz [@c, @b, @a]

Y

[@a, @b, @c].max 

regresarían @a

Esto es mucho más el " Ruby Way 'de las estructuras de datos anidados con lógica que depende de las posiciones en las matrices. Se necesita un poco más de trabajo al principio, pero lo encontrará mucho mejor en el largo plazo.

Ruby es un lenguaje de programación orientado a objetos y proporciona herramientas muy potentes para su uso. Recomiendo leer un libro como "The Ruby Programming Language" o "The Ruby Way" para obtener una descripción general del poder del idioma.

+0

El nombre 'Duo' no indica que ordenaría por el último elemento. ¿Qué pasa si alguien más creó un 'Duo' ordenado por el primer elemento para su parte del proyecto, lo que lleva a dos' Duo' diferentes? –

+0

Bueno, eso siempre va a ser un problema en cualquier código que escribas, si creas una clase y alguien más también la modifica, entonces tienes un problema. Pero esa no es una razón para no hacerlo. Por supuesto, esto fue solo un ejemplo. En la vida real, tendrías un nombre de clase mucho más descriptivo que en realidad describía lo que se estaba almacenando, no solo una tienda genérica de dos elementos. –

+0

Hola, muchas gracias por su respuesta. Me gusta mucho y estoy de acuerdo contigo, a la larga a veces es mejor. En esta ocasión, para mí, sin embargo, fue más rápido pasar el bloque. –

3

Si todo lo que necesita es mínimo y el máximo, es posible utilizar Enumerable#minmax método y calcular ambos a la vez:

min, max = arr.minmax {|a,b| a[1] <=> b[1]} 
#=> [[5, 1], [2, 7]] 
min 
#=> [5, 1] 
max 
#=> [2, 7] 

Editar: Hell, sólo notó también hay minmax_by, por lo que se puede combinar con last método, y tienen:

min, max = arr.minmax_by &:last 
Cuestiones relacionadas