Array slicing in Ruby: Erklärung für das unlogische Verhalten (entnommen aus Rubykoans.com)
Ging ich durch die übungen in Ruby Koans und ich war beeindruckt von den folgenden Ruby-quirk, fand ich wirklich unerklärliche:
array = [:peanut, :butter, :and, :jelly]
array[0] #=> :peanut #OK!
array[0,1] #=> [:peanut] #OK!
array[0,2] #=> [:peanut, :butter] #OK!
array[0,0] #=> [] #OK!
array[2] #=> :and #OK!
array[2,2] #=> [:and, :jelly] #OK!
array[2,20] #=> [:and, :jelly] #OK!
array[4] #=> nil #OK!
array[4,0] #=> [] #HUH?? Why's that?
array[4,100] #=> [] #Still HUH, but consistent with previous one
array[5] #=> nil #consistent with array[4] #=> nil
array[5,0] #=> nil #WOW. Now I don't understand anything anymore...
Also, warum ist array[5,0]
nicht gleich array[4,0]
? Gibt es einen Grund, warum array-slicing verhält sich dies seltsam, wenn Sie beginnen, auf die (Länge+1)th position??
Siehe auch Warum array.Scheibe Verhalten sich unterschiedlich (Länge, n)
sieht aus wie die erste Zahl ist der index zu Beginn an, die zweite Zahl gibt an, wie viele Elemente zu schneiden
sieht aus wie die erste Zahl ist der index zu Beginn an, die zweite Zahl gibt an, wie viele Elemente zu schneiden
InformationsquelleAutor Pascal Van Hecke | 2010-08-25
Du musst angemeldet sein, um einen Kommentar abzugeben.
Schneiden und Indizierung sind zwei verschiedene Vorgänge, und abzuleiten, der das Verhalten des einen vom anderen ist, wo dein problem liegt.
Das erste argument in der Scheibe erkennt nicht das element, sondern die Orte, die zwischen den Elementen und die Definition erstreckt (und nicht die Elemente selbst):
4 ist immer noch innerhalb des Arrays, gerade noch; wenn Sie Anfrage 0-Elemente, erhalten Sie das leere Ende des Arrays. Aber es gibt keinen index 5, man kann also nicht die Scheibe von dort.
Wenn Sie das tun-index (wie
array[4]
), Sie verweisen auf Elemente selbst, also die Indizes gehen nur von 0 bis 3.Ich habe gerade die Bestätigung von Charles Oliver Nutter (@headius auf Twitter), dass die Erklärung richtig ist. Er ist ein big-time-JRuby dev, so würde ich prüfen, sein Wort Recht MAßGEBEND.
Im folgenden ist die Begründung für dieses Verhalten: Klinge.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby - /ruby-talk/380637
Richtige Erklärung. Ähnliche Diskussionen auf ruby-core: redmine.ruby-lang.org/issues/4245 , redmine.ruby-lang.org/issues/4541
Auch bezeichnet als "Zaun-posten." Der fünfte Zaun-post (id 4) vorhanden ist, aber das fünfte element nicht. Slicing ist ein Zaun-post-operation, die Indizierung ist ein element der Bedienung.
InformationsquelleAutor Amadan
dies hat mit der Tatsache zu tun, dass die Scheibe ein array zurückgibt, relevante Quelle Dokumentation von Array#slice:
das lässt mich vermuten, dass, wenn Sie geben die start -, das ist außerhalb der Grenzen, wird es wieder null, also in deinem Beispiel
array[4,0]
bittet für das 4. element, das vorhanden ist, aber bittet um Rückgabe ein array mit null Elementen. Währendarray[5,0]
aufgefordert, einen index out of bounds, also es wird nil zurückgegeben. Dies macht das vielleicht mehr Sinn, wenn Sie sich daran erinnern, dass die slice-Methode ist wieder eine neue array, nicht änderung der ursprünglichen Datenstruktur.EDIT:
Nach der überprüfung der Kommentare, die ich beschlossen, zu Bearbeiten, zu beantworten. Scheibe ruft die folgende code-snippet, wenn die arg-Wert zwei:
wenn man sich in der
array.c
Klasse, wo dierb_ary_subseq
Methode definiert ist, sehen Sie, dass es ist die Rückgabe nil, wenn die Länge ist außerhalb der Grenzen, nicht der index:In diesem Fall das ist, was passiert, wenn 4 übergeben wird, prüft es, dass es 4 Elemente sind und daher löst keine der null-Rendite. Es geht dann auf und ein leeres array zurück, wenn das zweite argument auf null gesetzt ist. während, wenn 5 übergeben wird, es gibt nicht die 5 Elemente im array, so wird nil zurückgegeben, bevor der null-arg ausgewertet wird. code hier an der Linie 944.
Ich glaube, dass dies ein Fehler zu sein, oder zumindest unberechenbar und nicht das 'Prinzip der Geringsten Überraschung'. Wenn ich ein paar Minuten werde ich mindestens das Einreichen einer fehlerhaften test-patch auf ruby-core.
du hast Recht. Ich ging zurück und sah auf die Quelle, und es sieht aus wie das erste argument behandelt wird, innerhalb von c-code als die Länge, nicht der index. Ich passe meine Antwort, um dies zu reflektieren. Ich denke, das vorgelegt werden könnte als ein bug.
Verblüffende Verhalten
InformationsquelleAutor Jed Schneider
Zumindest beachten, dass das Verhalten konsistent ist. Von 5 auf bis alles wirkt gleich; die Verrücktheit tritt nur bei
[4,N]
.Vielleicht dieses Muster hilft, oder vielleicht bin ich einfach nur müde und es überhaupt nicht helfen.
In
[4,0]
, fangen wir mit dem Ende des Arrays. Würde ich finde es eigentlich ziemlich seltsam, so weit, wie die Schönheit in den mustern zu gehen, wenn der Letzte zurücknil
. Da von einem Zusammenhang wie diesem,4
ist eine akzeptable option für den ersten parameter, so dass die leeres array zurückgegeben werden können. Sobald wir die Treffer 5 und bis, obwohl, die Methode wahrscheinlich sofort beendet wird durch die Natur des seins ganz und völlig abwegig.InformationsquelleAutor Matchu
Dies macht Sinn, wenn man bedenkt, als ein array-slice kann ein Gültiger lvalue, nicht nur ein rvalue:
Dies wäre nicht möglich, wenn
array[4,0]
zurückgegebennil
statt[]
. Allerdingsarray[5,0]
zurücknil
weil es out of bounds (einfügen nach dem 4. element der 4-element-array sinnvoll ist, aber das einfügen nach dem 5. element der 4-element-array nicht).Lesen Sie die slice-syntax
array[x,y]
wie "ab nachx
Elemente inarray
wählen Sie bis zuy
Elemente". Dies ist nur sinnvoll, wennarray
hat mindestensx
Elemente.InformationsquelleAutor Frank Szczerba
Diese hat sinnvoll
Müssen Sie in der Lage sein zu ordnen, um diejenigen, die Scheiben, Sie sind also so definiert, dass der Beginn und das Ende der Zeichenfolge an der Arbeit mit null-Länge Ausdrücken.
array[5,0]=:foo # array is now [:peanut, :butter, :and, :jelly, nil, :foo]
was bedeutet die zweite Zahl soll bei der Zuordnung? es scheint, um ignoriert zu werden.
[26] pry(main)> array[4,5] = [:love, :hope, :peace] => [:peanut, :butter, :and, :jelly, :love, :hope, :peace]
es nicht ignoriert:
array = [:a, :b, :c, :d, :e]; array[1,2] = :x, :x; array => [:a, :x, :x, :d, :e]
InformationsquelleAutor DigitalRoss
Ich bin damit einverstanden, dass dies scheint wie ein seltsames Verhalten, aber auch die offizielle Dokumentation auf
Array#slice
zeigt das gleiche Verhalten, wie in Ihrem Beispiel, in "besonderen Fällen" unter:Leider, auch Ihre Beschreibung von
Array#slice
scheint nicht zu bieten jede Einsicht zu warum es funktioniert auf diese Weise:InformationsquelleAutor Mark Rushakoff
Fand ich die Erklärung von Gary Wright sehr hilfreich sein.
http://www.ruby-forum.com/topic/1393096#990065
Die Antwort von Gary Wright ist -
http://www.ruby-doc.org/core/classes/Array.html
Den docs könnte sicherlich mehr sein, klar, aber das tatsächliche Verhalten ist
selbst-konsistent und hilfreich.
Hinweis: ich gehe davon aus, 1.9.X-version von String.
Hilft es zu überlegen, die die Nummerierung in der folgenden Weise:
Dem gemeinsamen (und verständlichen) Fehler ist zu vermuten, dass die Semantik
das einzige argument index sind die gleichen wie die Semantik der
ersten argument in den beiden argument-Szenario (oder mehrere). Sie sind nicht
die gleiche Sache in der Praxis und in der Dokumentation nicht spiegeln dies wider.
Der Fehler ist aber auf jeden Fall in die Dokumentation und nicht in der
Umsetzung:
einziges argument: der index repräsentiert ein einzelnes Zeichen position
innerhalb der Zeichenfolge. Das Ergebnis ist entweder ein einzelnes Zeichen
gefunden auf der index oder null, denn es gibt kein Zeichen an der angegebenen
index.
beiden integer-Argumente: Argumente identifizieren, die einen Teil der Zeichenfolge
extrahieren oder zu ersetzen. Insbesondere die null-Breite Teile des Strings
kann auch identifiziert werden, so dass text eingefügt werden kann, die vor oder nach
bereits bestehende Charaktere, darunter an der front oder am Ende der Zeichenfolge. In diesem
Fall das erste argument ist nicht identifizieren, die eine Zeichenposition aber
stattdessen identifiziert der Platz zwischen den Zeichen, wie in der Abbildung gezeigt
oben. Das zweite argument ist die Länge, die kann 0 sein.
Das Verhalten eines Bereichs ist ziemlich interessant. Der Ausgangspunkt ist die
gleiche wie das erste argument, wenn zwei Argumente (wie beschrieben
oben), aber der Endpunkt der Strecke kann die "Zeichen position" als
mit Einzel-Indizierung oder die "edge position" mit zwei integer
Argumente. Der Unterschied wird festgestellt, ob die double-dot-Bereich
oder triple-Punkt-Bereich verwendet wird:
Wenn Sie wieder durch diese Beispiele und darauf bestehen und mit der single
index Semantik für die Doppel-oder range-Indizierung Beispiele werden Sie nur
verwirrt. Du hast die Verwendung des alternativen Nummerierung zeige ich in der
ascii-Diagramm-Modell das tatsächliche Verhalten.
InformationsquelleAutor vim
Einer Erklärung zur Verfügung gestellt von Jim Weirich
InformationsquelleAutor suvankar
Betrachten Sie das folgende array:
Können Sie ein Element einfügen, um den Anfang (Kopf) des Arrays durch Zuweisung
a[0,0]
. Setzen Sie das element zwischen"a"
und"b"
verwendena[1,0]
. Im Grunde, in der notationa[i,n]
,i
stellt einen index undn
eine Anzahl von Elementen. Wennn=0
es bezeichnet eine position, die zwischen den Elementen des Arrays.Nun, wenn Sie denken, über das Ende des Arrays, wie können Sie fügen Sie ein Element zu Ihrem Ende mit der notation oben beschrieben? Einfach, weisen Sie den Wert zu
a[3,0]
. Dies ist der Schwanz des Arrays.So, wenn Sie versuchen, Zugriff auf das element an
a[3,0]
erhalten Sie[]
. In diesem Fall sind Sie noch im Bereich des Arrays. Aber wenn Sie versuchen, Zugriff aufa[4,0]
erhalten Sienil
als return-Wert, da Sie nicht innerhalb des Bereichs der array nicht mehr.Lesen Sie mehr darüber auf http://mybrainstormings.wordpress.com/2012/09/10/arrays-in-ruby/ .
InformationsquelleAutor Tairone
tl;dr: in den source-code in
array.c
, unterschiedliche Funktionen aufgerufen werden, je nachdem, ob Sie pass 1 oder 2 Argumente inArray#slice
was in der unerwartete Werte zurückgeben.(First off, würde ich mag darauf hinweisen, dass ich keinen code in C, aber habe mit Ruby seit Jahren. Also, wenn Sie nicht vertraut sind mit C, aber nehmen Sie ein paar Minuten, um sich vertraut mit den Grundlagen von Funktionen und Variablen es ist wirklich nicht schwer, Folgen Sie den Ruby-source-code, wie unten gezeigt. Diese Antwort basiert auf Ruby v2.3, aber ist mehr oder weniger das gleiche zurück zu v1.9.)
Szenario #1
array.length == 4; array.slice(4) #=> nil
Wenn du dir den source-code für
Array#slice
(rb_ary_aref
), sehen Sie, dass, wenn nur ein argument übergeben wird (Linien 1277-1289),rb_ary_entry
genannt wird, vorbei an der index-Wert (das kann positiv oder negativ sein).rb_ary_entry
berechnet dann die position des gewünschten element aus dem Anfang des Arrays (in anderen Worten, wenn ein negativer Wert übergeben wird, wird er berechnet das positive äquivalent) und ruft dannrb_ary_elt
, um das angeforderte element.Als erwartet,
rb_ary_elt
zurücknil
wenn die Länge des arraylen
ist weniger als oder gleich der index (hier genanntoffset
).Szenario #2
array.length == 4; array.slice(4, 0) #=> []
Allerdings, wenn 2 Argumente übergeben werden (d.h. die Indexposition
beg
, und die Länge der Scheibelen
),rb_ary_subseq
genannt wird.In
rb_ary_subseq
, wenn der Start-indexbeg
ist größer als die array-Längealen
,nil
zurückgegeben:Sonst die Länge des slice
len
berechnet wird, und wenn es bestimmt zu null, wird ein leeres array zurückgegeben:So, da die Start-index von 4 ist nicht größer als
array.length
, wird ein leeres array zurückgegeben wird, anstatt desnil
Wert, dass man annehmen könnte.Frage beantwortet?
Wenn die eigentliche Frage hier ist nicht "Was code bewirkt, dass dies geschehen kann?", sondern vielmehr, "Warum hat Matz es so machen?", nun müssen Sie nur kaufen Sie ihm eine Tasse Kaffee an der nächsten RubyConf und ihn Fragen.
InformationsquelleAutor Scott Schupbach