Comment fonctionne Array # sort quand un bloc est passé?

J’ai du array.sort{ |x,y| block } comprendre comment array.sort{ |x,y| block } array.sort{ |x,y| block } fonctionne exactement, d’où 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 ton exemple

 a.sort 

est équivalent à

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

Comme vous le savez, pour sortinger un tableau, vous devez être capable de comparer ses éléments (si vous en doutez, essayez d’implémenter tout algorithme de sorting sans utiliser de comparaison, non < , > , < = ou >= ).

Le bloc que vous fournissez est vraiment une fonction qui sera appelée par l'algorithme de sort pour comparer deux éléments. C'est-à-dire que x et y seront toujours des éléments du tableau d'entrée choisis par l'algorithme de sort lors de son exécution.

L'algorithme de sort supposera que cette fonction / bloc de comparaison répondra aux exigences de la méthode < => :

  • retourne -1 si x
  • retourne 0 si x = y
  • retourne 1 si x> y

Si vous ne fournissez pas une fonction ou un bloc de comparaison adéquat, vous obtiendrez un tableau dont l’ordre est indéfini.

Vous devriez maintenant comprendre pourquoi

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

et

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

renvoyer 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:

  1. Vous pouvez inclure le module Comparable dans votre classe qui définira automatiquement pour vous les méthodes suivantes: , == , >= , < , < = et > .
  2. Les instances de votre classe peuvent maintenant être sortingées en utilisant l'invocation par défaut (c'est-à-dire sans argument) pour sort .

Notez que la méthode < => est déjà fournie là où elle a du sens dans la bibliothèque standard de Bignum ( Bignum , Array , File::Stat , Fixnum , Ssortingng , Time , etc.).

Lorsque vous devez sortinger un tableau d’entiers, disons, des entiers, il est assez simple pour la méthode de sort de sort les éléments correctement – des nombres plus petits en premier, plus grands à la fin. C’est à ce moment que vous utilisez un sort ordinaire, sans bloc.

Mais lorsque vous sortingez d’autres objects, il peut être nécessaire de fournir un moyen de comparer (chacun) deux d’entre eux. Disons que vous avez un tableau d’objects de classe Person . Vous ne pouvez probablement pas dire si object bob est plus grand que object mike (c’est-à-dire que la classe Person n’a pas la méthode < => implémentée). Dans ce cas, vous devez fournir un code pour expliquer dans quel ordre vous voulez que ces objects soient sortingés pour la méthode de sort . C’est là que la forme du 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 de sort sortinge de la même manière – le même algorithme est utilisé. Ce qui est différent est la logique de comparaison.

< => est une méthode ruby ​​qui retourne ( self.< =>( argument ) < => self.< =>( argument ) )

  • -1 si self
  • 0 si self == argument
  • 1 si soi> argument

x et y sont des éléments de tableau. Si aucun bloc n’est fourni, la fonction de 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 un smth qui est <0, x est considéré <

La réponse de @OscarRyz m’a beaucoup éclairé sur la façon dont le sorting fonctionne, en particulier

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

D’après ce que j’ai compris, je fournis ici l’état de la masortingce après chaque comparaison pour les résultats de blocs ci-dessus.

Note: Vous avez la référence pour imprimer les valeurs des parameters de bloc e1, e2 depuis ruby-forum

 1.9.3dev :001 > a = %w(deawfk) 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é à 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

Quelques points divers:

  • x et y sont appelés parameters de bloc. La méthode de sorting dit fondamentalement “Je vais vous donner x et y, vous déterminez si x ou y doit venir en premier, et je vais m’occuper des choses ennuyeuses en ce qui concerne le sorting”
  • < => s’appelle un 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 sorting.

Ceci est utile pour définir pour les classes personnalisées quel élément devrait être avant l’autre.

Pour les données de base (nombres, chaînes de caractères, date, etc.), l’ordre naturel est prédéfini, mais pour l’élément client (employé, par exemple), vous définissez qui va avant 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 “supérieure” iront en premier) plutôt que l’ordre naturel ( x< =>y )

La méthode < => signifie “compareTo” et renvoie 0 si les éléments sont équivalents, ou < 0 si x passe avant y ou > 0 si x va après y

Je crois | 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 Disons avec [“d”, “a”, “e”, “c”, “b”], “d” et “a” semblent être comparés en premier. Puis, comme il est décroissant, les deux restnt dans le même ordre car d est inférieur à a. Ensuite, d et e sont évalués. “e” est déplacé à la position “d”. Sans connaître le fonctionnement interne du code c, il est impossible de savoir où d est déplacé, mais je pense que ce processus continue jusqu’à ce que tous les éléments soient sortingé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); }