J'ai du mal à comprendre comment array.sort{ |x,y| block }
fonctionne exactement, donc comment l'utiliser?
Un exemple de documentation Ruby :
a = [ "d", "a", "e", "c", "b" ]
a.sort #=> ["a", "b", "c", "d", "e"]
a.sort { |x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
Dans votre exemple
a.sort
est équivalent à
a.sort { |x, y| x <=> y }
Comme vous le savez, pour trier un tableau, vous devez pouvoir comparer ses éléments (si vous en doutez, essayez simplement d'implémenter n'importe quel algorithme de tri sans utiliser de comparaison, pas de <
, >
, <=
ou >=
).
Le bloc que vous fournissez est vraiment une fonction qui sera appelée par l'algorithme sort
pour comparer deux éléments. C'est-à-dire x
et y
seront toujours certains éléments du tableau d'entrée choisis par l'algorithme sort
lors de son exécution.
L'algorithme sort
supposera que cette fonction/bloc de comparaison répondra aux exigences de la méthode <=>
:
Le défaut de fournir une fonction/bloc de comparaison adéquate entraînera un tableau dont l'ordre n'est pas défini.
Vous devez maintenant comprendre pourquoi
a.sort { |x, y| x <=> y }
et
a.sort { |x, y| y <=> x }
renvoie le même tableau dans des ordres opposés.
Pour développer ce que Tate Johnson a ajouté, si vous implémentez la fonction de comparaison <=>
sur n'importe laquelle de vos classes, vous gagnez ce qui suit
Comparable
dans votre classe qui définira automatiquement pour vous les méthodes suivantes: between?
, ==
, >=
, <
, <=
et >
.sort
.Notez que le <=>
la méthode est déjà fournie partout où elle a du sens dans la bibliothèque standard de Ruby (Bignum
, Array
, File::Stat
, Fixnum
, String
, Time
, etc ...).
Lorsque vous avez un tableau, disons, d'entiers à trier, il est assez simple pour la méthode sort
de classer correctement les éléments - des nombres plus petits en premier, plus gros à la fin. C'est alors que vous utilisez un sort
ordinaire, sans bloc.
Mais lorsque vous triez d'autres objets, il peut être nécessaire de fournir un moyen de comparer (chacun) deux d'entre eux. Supposons que vous ayez un tableau d'objets de classe Person
. Vous ne pouvez probablement pas dire si l'objet bob
est supérieur à l'objet mike
(c'est-à-dire que la classe Person
n'a pas la méthode <=>
mis en œuvre). Dans ce cas, vous devrez fournir du code pour expliquer dans quel ordre vous voulez que ces objets soient triés selon la méthode sort
. C'est là que la forme de bloc entre en jeu.
people.sort{|p1,p2| p1.age <=> p2.age}
people.sort{|p1,p2| p1.children.count <=> p2.children.count}
etc. Dans tous ces cas, la méthode sort
les trie de la même manière - le même algorithme est utilisé. Ce qui est différent, c'est la logique de comparaison.
La réponse de @OscarRyz m'a beaucoup éclairé sur la question du fonctionnement du tri, en particulier
{ |x, y| y <=> x }
Sur la base de ma compréhension, je fournis ici l'état de la matrice après chaque comparaison pour les résultats de bloc ci-dessus.
Remarque: Vous avez la référence d'impression des valeurs des paramètres de bloc 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 état de tableau deviné au moment de l'exécution après chaque comparaison:
[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)
Merci,
Jignesh
<=>
Est une méthode Ruby qui renvoie (self.<=>( argument )
)
x
et y
sont des éléments du tableau. Si aucun bloc n'est fourni, la fonction sort
utilise x<=>y
, Sinon le résultat du bloc indique si x doit être avant y.
array.sort{|x, y| some_very_complicated_method(x, y) }
Ici, si some_very_complicated_method (x, y) renvoie smth qui est <0, x est considéré <que y et ainsi de suite ...
Quelques points divers:
x
et y
sont appelés paramètres de bloc. La méthode de tri dit essentiellement "Je vais vous donner x et y, vous déterminez si x ou y doit venir en premier, et je m'occuperai des trucs ennuyeux en ce qui concerne le tri"<=>
est appelé opérateur de vaisseau spatial .Dans:
a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
qu'est-ce que x et y?
x
et y
sont les éléments comparés par l'algorithme de tri.
Ceci est utile pour définir pour les classes personnalisées quel élément doit être avant l'autre.
Pour les données de base (nombres, chaînes, date, etc.), l'ordre naturel est prédéfini, mais pour l'élément client (c'est-à-dire l'employé), vous définissez qui précède qui dans une comparaison. Ce bloc vous donne la chance de définir cela.
et que se passe-t-il à y <=> x?
Là, ils comparent les éléments dans l'ordre décroissant (ceux avec une valeur "plus élevée" iront en premier) plutôt que dans l'ordre naturel (x<=>y
)
Le <=>
méthode signifie "compareTo" et retourne 0 si les éléments sont équivalents, ou <
0 si x
va avant que y
ou >
0 si x
va après y
Je crois que | x, y | y <=> x compare deux éléments à la fois dans l'ordre décroissant, comme indiqué dans: http://www.Ruby-doc.org/core-1.9.3/Array.html#method-i- 3C-3D-3E Dites avec ["d", "a", "e", "c", "b"], "d" et "a" semblent être comparés en premier. Puisqu'il descend, les deux restent dans le même ordre car d est évalué à moins que a. Ensuite, d et e sont évalués. "e" est déplacé vers la position "d". Sans connaître le fonctionnement interne du code c, il n'est pas possible de savoir où est déplacé d mais je pense que ce processus continue jusqu'à ce que tous les éléments soient triés. Les fonctions 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);
}