ruby's = Operator und Sortiermethode

8
%Vor%

Oben habe ich einige Player-Objekte erstellt und sie zu dem zuvor leeren Array @players hinzugefügt.

Dann habe ich & lt; = & gt; um das zu sein:

%Vor%

Ich kann dann diesen Code ausführen

%Vor%

und mein Array von Spielerobjekten in @players wird von Highscore zu Lowscore sortiert. Ich schätze, das sieht für mich etwas bockig aus. Ich bin ein wenig unklar, was hier vor sich geht. Wie finde ich heraus, was hinter den Kulissen vor sich geht?

Alles, was ich weiß, ist, dass wenn Sie zwei Werte nehmen und den Raumschiffoperator / allgemeinen Vergleichsoperator verwenden:

%Vor%

Manchmal scheint es so, als hätte Ruby eine Menge Low-Level-Sachen, die ich auf dem hohen Niveau, auf dem ich programmiere, nicht sehen kann. Das scheint natürlich ... aber dieser Fall scheint besonders von der unteren Ebene entfernt zu sein geht auf die Sortiermethode. Wie benutzt man den Raumschiffoperator? Warum wird der Raumschiffoperator auf die Art und Weise neu definiert, wie wir Objekte jetzt sortieren können?

    
Jwan622 27.10.2014, 05:26
quelle

3 Antworten

31

Bevor Sie das Sortieren von Objekten verstehen können. Sie müssen die .sort-Methode in Ruby verstehen. Wenn Sie 5 Karten mit Zahlen sortieren würden, könnten Sie sich alle ansehen, die niedrigste leicht finden und diese als Ihre erste Karte wählen (vorausgesetzt, Sie sortieren vom niedrigsten zum höchsten Wert, dem Ruby) tut). Wenn dein Gehirn sortiert, kann es alles betrachten und von dort sortieren.

Hier gibt es zwei Hauptelemente der Verwirrung, die selten angesprochen werden:

1) Ruby kann nicht so sortieren, wie Sie das Wort "sort" finden. Ruby kann nur Array-Elemente austauschen und Array-Elemente vergleichen.

2) Ruby verwendet einen Vergleichsoperator, das sogenannte Raumschiff, um Zahlen zu benennen, um das Sortieren zu erleichtern. Diese Zahlen sind -1,0,1. Leute denken fälschlicherweise, dass diese 3 Zahlen es "sortieren" (zB wenn es ein Array mit 3 Zahlen wie 10,20,30 gäbe, dann wäre die 10 eine -1, die 20 eine 0 und die 30 eine 1 , und Ruby vereinfacht nur das Sortieren, indem es auf -1,0,1 reduziert wird.Dies ist falsch.Rubin kann nicht "sortieren". Es kann nicht nur vergleichen).

Betrachte den Raumschiffoperator. Es sind 3 einzelne Operatoren, die in eins zusammengefasst sind, das & lt ;, das = und das & gt ;. Wenn Ruby zwei Variablen vergleicht, ergibt sich eine dieser Zahlen.

Was bedeutet "Ergebnisse"? Es bedeutet NICHT, dass einer der Variablen eine 0, 1, -1 zugewiesen wird. Es ist einfach ein Weg, wie Ruby zwei Variablen nehmen und etwas damit machen kann. Jetzt, wenn Sie nur ausführen:

%Vor%

Sie erhalten das Ergebnis -1, da jeder 'Teil' (zB & lt ;, = oder & gt;) des Vergleichsoperators (Raumschiff) wahr ist, erhält die Nummer, die ihm zugewiesen ist (wie gesehen) im obigen Bild). Wenn Ruby dies sieht & lt; = & gt; Mit einem Array hat es jedoch zwei Dinge, die es nur mit dem Array tun wird: Lassen Sie das Array alleine oder tauschen Sie die Elemente des Arrays aus.

Wenn Ruby das & lt; = & gt; und bekommt eine 1, es wird die 2 Elemente des Arrays tauschen. Wenn Ruby ein Ergebnis von -1 oder 0 erhält, wird das Array allein gelassen.

Ein Beispiel ist, wenn Ruby das Array [2,1] sieht. Die Sortiermethode würde dazu führen, dass diese Zahlen wie 2 & lt; = & gt; 1 herangezogen werden. Da der Teil des Raumschiffs (wenn du so darüber nachdenken willst) wahr ist, ist das & gt; (dh 2 & gt; 1 ist wahr), das Ergebnis ist '1' von Ruby. Wenn Ruby ein 1-Ergebnis vom Raumschiff sieht, tauscht es die 2 Elemente des Arrays aus. Jetzt ist das Array [1,2].

Hoffentlich sehen Sie, dass Ruby nur mit dem & lt; = & gt; Operator, und dann tauscht (oder verlässt) die 2 Elemente in dem Array, das es vergleicht.

Verstehen Sie, dass die .sort-Methode eine iterative Methode ist, was bedeutet, dass es sich um eine Methode handelt, die einen Codeblock mehrmals ausführt. Die meisten Leute werden mit der .sort-Methode erst vertraut gemacht, nachdem sie Methoden wie .each oder .upto gesehen haben (Sie müssen nicht wissen, was diese tun, wenn Sie noch nichts von ihnen gehört haben), aber diese Methoden laufen durch das Array nur einmal. Die .sort-Methode unterscheidet sich dadurch, dass sie Ihr Array so oft durchläuft, wie es benötigt wird, damit es sortiert wird (nach Sortierung meinen wir, dass es verglichen und getauscht wird).

Um sicherzustellen, dass Sie die Ruby-Syntax verstehen:

%Vor%

Der Codeblock (umgeben von {} 's) ist, was Ruby tun würde, wenn er vom niedrigsten zum höchsten sortiert. Aber es genügt zu sagen, dass die erste Iteration der .sort-Methode die Variablen zwischen den Pipes (a, b) den ersten beiden Elementen des Arrays zuweisen wird. Für die erste Iteration a = 4 und b = 5, und da 4 & lt; 5, ergibt dies eine -1, was Ruby bedeutet, das Array NICHT zu tauschen. Dies geschieht für eine zweite Iteration, dh a = 5 und b = 6, sieht, dass 5 & lt; 6, ergibt -1 und lässt das Array alleine. Da alle & lt; = & gt; Ergebnisse waren -1, Ruby hört auf, durchzulaufen und fühlt, dass das Array nach [4,5,6] sortiert ist.

Wir können von hoch nach niedrig sortieren, indem wir einfach die Reihenfolge der Variablen vertauschen.

%Vor%

Hier ist was Ruby macht:

Iteration 1: Array [ 5,1 , 9]. a = 5, b = 1. Ruby sieht b & lt; = & gt; a und sagt 1 & lt; 5? Ja. Das ergibt -1. Gleich bleiben.

Iteration 2: Array [5, 1,9 ]. a = 1, b = 9. Ruby sieht b & lt; = & gt; a und sagt 9 & lt; 1? Nein. Das führt zu 1. Tausche die 2 Array-Elemente. Das Array ist jetzt [5,9,1]

Iteration 3: Array [ 5,9 , 1]. Beginnend mit b / c gab es ein +1 im Array, bevor man alles durchging. a = 5, b = 9. Ruby sieht das b & lt; = & gt; a, sagt 9 & lt; 5? Nein. Das führt zu 1. Swap. [9, 5, 1] ​​

Iteration 4: Array [9, 5,1 ]. a = 5, b = 1. Ruby sieht das b & lt; = & gt; a, sagt 1 & lt; 5? Ja. Das ergibt -1. Daher wird kein Austausch durchgeführt. Erledigt. [9,5,1].

Stellen Sie sich ein Array mit der Zahl 50 für die ersten 999 Elemente und eine 1 für Element 1000 vor.Sie verstehen die Sortiermethode vollständig, wenn Sie erkennen, dass Ruby dieses Array tausende Male durchlaufen muss, indem es die gleiche einfache Vergleichs- und Auslagerungsroutine ausführt, um das 1 bis zum Anfang des Arrays.

Nun können wir uns endlich .sort ansehen, wenn wir zu einem Objekt kommen.

%Vor%

Dies sollte jetzt ein wenig mehr Sinn machen. Wenn die Methode .sort für ein Objekt aufgerufen wird, z. B. wenn Sie Folgendes ausführen:

%Vor%

zieht den "def & lt; = & gt;" Methode mit dem Parameter (zB 'other'), der das aktuelle Objekt von @players hat (z. B. was auch immer das aktuelle Instanzobjekt von '@players' ist, da es die Sortiermethode ist, wird es letztendlich alle durchlaufen Elemente des '@players'-Arrays). Wenn Sie versuchen, die Methode puts für eine Klasse auszuführen, ruft sie automatisch die Methode to_s innerhalb dieser Klasse auf. Das gleiche gilt für die .sort-Methode, die automatisch nach dem & lt; = & gt; Methode.

Betrachten Sie den Code innerhalb der & lt; = & gt; Methode muss eine .score-Instanzvariable (mit einer Accessor-Methode) oder einfach eine .score-Methode in dieser Klasse vorhanden sein. Und das Ergebnis dieser .score-Methode sollte (hoffentlich) ein String oder eine Zahl sein - die 2 Dinge, die Rubin "sortieren" kann. Wenn es eine Zahl ist, verwendet Ruby es & lt; = & gt; Operation "sortieren", um alle diese Objekte neu anzuordnen, da sie nun wissen, welcher Teil dieser Objekte sortiert werden soll (in diesem Fall ist dies das Ergebnis der .score-Methode oder der Instanzvariablen).

Als letzten Leckerbissen sortiert Ruby alphabetisch, indem es auch in numerische Werte konvertiert wird. Es berücksichtigt nur, dass jedem Buchstaben der Code aus ASCII zugewiesen wird (da Großbuchstaben niedrigere Zahlenwerte auf dem ASCII-Code-Diagramm haben, wird in Großbuchstaben standardmäßig zuerst sortiert).

Hoffe, das hilft!

    
Tony DiNitto 18.01.2015, 20:31
quelle
2

In Ihrem Beispiel

%Vor%

entspricht

%Vor%

Die Elemente werden abhängig von der Rückgabe der Methode <=> sortiert. Wenn <=> -1 zurückgibt, wird das erste Element vor dem zweiten Element sortiert, wenn es 1 zurückgibt, wird das zweite Element vor dem ersten Element sortiert. Wenn Sie den Rückgabewert ändern (z. B. die Elemente tauschen), ändert sich die Reihenfolge entsprechend den Rückgabewerten.

    
spickermann 27.10.2014 05:42
quelle
0

sort ist eigentlich eine Enumerable-Methode, die auf der Implementierung beruht von <=> . Von Ruby doc selbst:

  

Wenn Enumerable # max, #min oder #sort verwendet wird, werden die Objekte in der   Sammlung muss auch eine sinnvolle & lt; = & gt; Betreiber, wie diese   Methoden beruhen auf einer Reihenfolge zwischen Mitgliedern der Sammlung.

Probieren Sie es selbst aus:

%Vor%

Wenn Sie sort für @players array verwenden, wird das Objekt Player mit <=> aufgerufen. Wenn Sie es nicht implementieren, erhalten Sie wahrscheinlich:

  

player.rb: 14: in sort': comparison of Player with Player failed (ArgumentError) from player.rb:14:in '

Das macht Sinn, da das Objekt nicht mit <=> umgehen kann.

    
Surya 27.10.2014 06:03
quelle

Tags und Links