2010-04-14 8 views

Respuesta

119

En su ejemplo

a.sort 

es equivalente a

a.sort { |x, y| x <=> y } 

Como saben, ordenar una matriz, es necesario poder para comparar sus elementos (si lo dudas, simplemente intenta implementar cualquier algoritmo de ordenación sin usar ninguna comparación , no <, >, <= o >=).

El bloque que proporciona es realmente una función que será llamada por el algoritmo sort para comparar dos elementos. Eso es x y y siempre serán algunos elementos de la matriz de entrada elegida por el algoritmo sort durante su ejecución.

El algoritmo sort asumirá que esta función de comparación/bloque cumplirá con los requisitos para el método <=>:

  • retorno -1 si x < y
  • retorno 0 si x = y
  • retorno 1 si x> y

Si no se proporciona una función/bloque de comparación adecuada, se obtendrá una matriz cuya o der no está definido.

Ahora debe entender por qué

a.sort { |x, y| x <=> y } 

y

a.sort { |x, y| y <=> x } 

retorno de la misma matriz en órdenes opuestas.


dar más detalles sobre lo que agregó Tate Johnson, si se implementa la función de comparación <=> en cualquiera de sus clases, se obtiene la siguiente

  1. Usted puede incluir el módulo Comparable en su clase que automáticamente defina los siguientes métodos: between?, ==, >=, <, <= y >.
  2. Las instancias de su clase ahora se pueden ordenar utilizando la invocación predeterminada (es decir, sin argumento) al sort.

Tenga en cuenta que ya se proporciona el método <=> dondequiera que tenga sentido en la biblioteca estándar de rubí (Bignum, Array, File::Stat, Fixnum, String, Time, etc ...).

+1

Creo que vale la pena agregar que '<=>' es un método definido en 'Comparable' y mezclado con' String'. 'Fixnum' y' Bignum' también definen '<=>'. Puede implementar '<=>' en cualquier clase donde la ordenación o las comparaciones sean necesarias. –

+0

He resaltado la oración importante. xey serán 2 elementos de su matriz, elegidos por el algoritmo de ordenamiento en sí. – bltxd

+0

Gracias. ¡Ahora lo entiendo! –

6

<=> es un método es rubí que devuelve (self.<=>(argument))

  • -1 si auto < argumento
  • 0 si auto == argumento
  • 1 si auto> argumento

x y y son elementos de matriz. Si no se proporciona ningún bloque, la función sort usa x<=>y, de lo contrario, el resultado del bloque indica si x debe estar antes de y.

array.sort{|x, y| some_very_complicated_method(x, y) } 

Aquí si some_very_complicated_method (x, y) devuelve Smth que es < 0, x se considera que y < y así sucesivamente ...

20

Cuando se tiene una serie de, digamos, los números enteros a ordenar, es bastante sencillo para el método sort ordenar los elementos correctamente: números más pequeños primero, más grandes al final. Es entonces cuando usa el ordinario sort, sin bloqueo.

Pero cuando ordena otros objetos, puede ser necesario proporcionar una forma de comparar (cada uno) dos de ellos. Supongamos que tiene una matriz de objetos de la clase Person. Probablemente no pueda saber si el objeto bob es mayor que el objeto mike (es decir, la clase Person no tiene implementado el método <=>). En ese caso, deberá proporcionar algún código para explicar en qué orden desea ordenar estos objetos según el método sort. Ahí es donde la forma de bloque entra en acción

people.sort{|p1,p2| p1.age <=> p2.age} 
people.sort{|p1,p2| p1.children.count <=> p2.children.count} 

etc. En todos estos casos, los ordena sort método de la misma manera -. Se utiliza el mismo algoritmo. Lo que es diferente es la lógica de comparación.

+0

Encontré esta respuesta mucho más útil para ser sincero. Una imagen vale más que mil palabras y un ejemplo habla mil líneas de explicación. –

+0

Nota: 'people.sort {| p1, p2 | p1.age <=> p2.age} 'podría volver a escribirse como' people.sort_by {| p | p.age} ' – Cyoce

4

Algunos puntos diversos:

  • x y y se llaman parámetros de bloque. El método de clasificación básicamente dice "Te daré xey, tú determinas si x o y debería ser lo primero, y yo cuidaré las cosas aburridas con respecto a la clasificación"
  • <=> se llama spaceship operator.
3

En:

a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] 

lo que es X e Y?

x y y son los elementos que se comparan por el algoritmo de clasificación.

Esto es útil para definir clases personalizadas cuyo elemento debe estar antes que el otro.

Para datos básicos (números, cadenas, fecha, etc.) el orden natural está predefinido, pero para el elemento del cliente (es decir, Empleado) se define quién va antes que en una comparación. Este bloque te da la oportunidad de definir eso.

y lo que sucede en y < => x?

Allí, se están comparando los elementos en orden (los que tienen valor "superior" se irá primero) más que el orden natural descendente (x<=>y)

El método <=> significa "compareTo" y el retorno 0 si los elementos son equivalentes, o 0 si <x va delante de y o > 0 si x va tras y

2

creo | x, y | y < => x está comparando dos elementos a la vez en orden descendente, como se ve en: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-3C-3D-3E Diga con ["d", "a", "e", "c", "b"], "d" y "a" parecen ser comparados primero. Entonces, dado que está descendiendo, ambos permanecen en el mismo orden porque d evalúa a menos de a. Entonces d y e son evaluados. "e" se mueve a la posición "d". Sin conocer el funcionamiento interno del código c, no es posible saber hacia dónde se movió, pero creo que este proceso continúa hasta que se hayan ordenado todos los elementos. Las funciones c:

  VALUE 
rb_ary_cmp(VALUE ary1, VALUE ary2) 
{ 
    long len; 
    VALUE v; 

    ary2 = rb_check_array_type(ary2); 
    if (NIL_P(ary2)) return Qnil; 
    if (ary1 == ary2) return INT2FIX(0); 
    v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2); 
    if (v != Qundef) return v; 
    len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2); 
    if (len == 0) return INT2FIX(0); 
    if (len > 0) return INT2FIX(1); 
    return INT2FIX(-1); 
} 
7

@OscarRyz respuesta sobre aclararon mucho por mí sobre la cuestión de cómo funciona la clase, esp

{ |x, y| y <=> x } 

Basado en mi conocimiento que estoy proporcionando aquí lo que el estado de la array sería después de cada comparación para los resultados de bloque anteriores.

Nota: Tienes la referencia de la impresión de los valores de parametros de bloque e1, e2 de ruby-forum

1.9.3dev :001 > a = %w(d e a w f k) 
1.9.3dev :003 > a.sort { |e1, e2| p [e2, e1]; e2 <=> e1 } 
["w", "d"] 
["k", "w"] 
["k", "d"] 
["k", "e"] 
["k", "f"] 
["k", "a"] 
["f", "a"] 
["d", "f"] 
["d", "a"] 
["d", "e"] 
["e", "f"] 
=> ["w", "k", "f", "e", "d", "a"] 

Un estado array supuso en tiempo de ejecución después de cada comparación:

[e2, e1] Comparsion Result  Array State 
["w", "d"]  1     ["w", "e", "a", "d", "f", "k"] 
["k", "w"]  -1     ["w", "e", "a", "d", "f", "k"] 
["k", "d"]  1     ["w", "e", "a", "k", "f", "d"] 
["k", "e"]  1     ["w", "k", "a", "e", "f", "d"] 
["k", "f"]  1     ["w", "k", "a", "e", "f", "d"]  
["k", "a"]  1     ["w", "k", "a", "e", "f", "d"] 
["f", "a"]  1     ["w", "k", "f", "e", "a", "d"] 
["d", "f"]  -1     ["w", "k", "f", "e", "a", "d"] 
["d", "a"]  1     ["w", "k", "f", "e", "d", "a"] 
["d", "e"]  -1     ["w", "k", "f", "e", "d", "a"] 
["e", "f"]  -1     ["w", "k", "f", "e", "d", "a"] (Result) 

Gracias,

Jignesh

Cuestiones relacionadas