Warum beginnt der neue Hat-Operator-Index der C # 8-Array-Slicing-Funktion nicht bei 0?

156

C # 8.0 bietet eine bequeme Möglichkeit zum Schneiden von Arrays - siehe offiziellen C # 8.0-Blogpost .

Die Syntax für den Zugriff auf das letzte Element eines Arrays lautet

int value[] = { 10, 11, 12, 13 };

int a = value[^1]; // 13
int b = value[^2]; // 12

Ich frage mich, warum die Indizierung für den Rückwärtszugriff auf die Elemente bei 1 statt bei 0 beginnt. Gibt es dafür einen technischen Grund?

Michael Pittino
quelle
11
Beachten Sie, dass auch C ++ - Bereiche vorhanden sind [beginInclusive, endExclusive). Es ist eine übliche Konvention.
Bommelding
3
@Sinatr: Basierend auf diesem Blog-Beitrag wäre die Syntax, um alles zurückzugeben value[0..^0], da der Endindex exklusiv ist (so funktionieren auch die meisten anderen Sprachen). Außerdem erhalten Sie bequemerweise value[^i..^0]die letzten iArtikel.
BlueRaja - Danny Pflughoeft
1
@bommelding: C ++ ist rbegin()mit dieser Vorstellung nicht einverstanden - das erste Element außerhalb dieses Bereichs ist auch nicht das One-Beyond-the-End. ;-)
DevSolar
1
Oh cool, das sieht aus wie das Äquivalent einer negativen Indizierung in Python:value[-1] # 13
CS95
1
@coldspeed Und in Ruby das gleiche wie in Python. Ich vermute, beide haben diese Konvention von Perl ausgeliehen.
Wayne Conrad

Antworten:

170

Offizielle Antwort

Zur besseren Sichtbarkeit hier ein Kommentar von Mads Torgersen , der diese Entwurfsentscheidung aus dem C # 8-Blogbeitrag erläutert :

Wir haben uns entschieden, Python zu folgen, wenn es um die Arithmetik von Anfang bis Ende geht. 0 bezeichnet das erste Element (wie immer) und  ^0 das "Länge" -Element, dh das Element direkt am Ende. Auf diese Weise erhalten Sie eine einfache Beziehung, bei der die Position eines Elements vom Anfang plus seine Position vom Ende der Länge entspricht. Das  x In  ^x ist das, was Sie von der Länge abgezogen hätten, wenn Sie die Mathematik selbst durchgeführt hätten.

Warum nicht das Minuszeichen ( -) anstelle des neuen ^Operators hat ( ) verwenden? Dies hat vor allem mit Reichweiten zu tun. Wieder im Einklang mit Python und den meisten Branchen möchten wir, dass unsere Sortimente am Anfang inklusive und am Ende exklusiv sind. Welchen Index geben Sie an, um zu sagen, dass ein Bereich bis zum Ende reichen soll? In C # ist die Antwort einfach: x..^0geht von  x bis zum Ende. In Python gibt es keinen expliziten Index, den Sie angeben können: Funktioniert -0nicht, da er 0dem ersten Element entspricht! In Python müssen Sie also den Endindex vollständig weglassen, um einen Bereich auszudrücken, der bis zum Ende reicht : x... Wenn das Ende des Bereichs berechnet wird, müssen Sie daran denken, eine spezielle Logik zu haben, falls dies herauskommt 0. Wie in x..-y, woywurde berechnet und kam heraus 0. Dies ist ein häufiges Ärgernis und eine Fehlerquelle.

Beachten Sie schließlich, dass Indizes und Bereiche in .NET / C # erstklassige Typen sind. Ihr Verhalten ist nicht an das gebunden, worauf sie angewendet werden oder sogar in einem Indexer verwendet werden sollen. Sie können Ihren eigenen Indexer, der Index verwendet, und einen anderen, der Index verwendet, vollständig definieren Range- und wir werden solche Indexer z  Span. Sie können aber auch Methoden verwenden, die beispielsweise Bereiche annehmen.

Meine Antwort

Ich denke, dies entspricht der klassischen Syntax, die wir gewohnt sind:

value[^1] == value[value.Length - 1]

Wenn 0 verwendet würde, wäre es verwirrend, wenn die beiden Syntaxen nebeneinander verwendet würden. Auf diese Weise hat es eine geringere kognitive Belastung.

Andere Sprachen wie Python verwenden dieselbe Konvention.

Martin Zikmund
quelle
13
Kleinere Korrektur des Mads-Kommentars: Sie müssen den Endindex in Python nicht vollständig weglassen. Sie können Noneanstelle einer Nummer verwenden : [0,1,2,3,4][2:None] == [2,3,4]. Aber ja, Sie können keine Ganzzahl als Endindex verwenden (ohne die Länge offensichtlich zu berechnen).
Giacomo Alzetta
4
Warten Sie .. was ist los mit x..? Das scheint in Ordnung zu sein und ich hatte nie Probleme mit der Python- [3:]Syntax.
Mowwwalker
8
@mowwwalker - ist das nicht schon im Zitat enthalten? "Also in Python ... Wenn das Ende des Bereichs berechnet wird, müssen Sie daran denken, eine spezielle Logik zu haben, falls es zu 0 kommt"
Damien_The_Unbeliever
3
@mowwwalker Mads Kommentar betraf Fälle, in denen Sie nicht wissen, wie der Indexwert aussehen wird, weil er auf irgendeine Weise berechnet wurde. Sie sagen, dass in dem Fall, in dem Sie endIndexals negativer Index berechnen möchten (dh als Index vom Ende), eine Diskontinuität zwischen negativen und positiven Zahlen 0auftritt, da dies in diesem Fall nicht richtig funktioniert. Als ich darauf hinwies , müssen Sie ersetzen 0durch Nonedafür. Dies bedeutet, dass Ihr Code beispielsweise so aussehen sollte seq[startIndex:endIndex or None]. Das or Nonesollte weggelassen werden, wenn endIndexerwartet wird, dass es positiv ist.
Giacomo Alzetta
5
Es ist gut zu sehen, dass sie Pythons Fehler mit der Sache -0 nicht wiederholen. Die Behandlung dieses Sonderfalls ist ein großer Aufwand und viel zu leicht zu vergessen.
user2357112 unterstützt Monica