Tipps zum Golfen in R


58

Ich bin auf der Suche nach Tipps zum Golfen in der statistischen Sprache R. R ist vielleicht eine unkonventionelle Wahl für Golf. Es erledigt jedoch bestimmte Dinge sehr kompakt (Sequenzen, Zufälligkeiten, Vektoren und Listen), viele der eingebauten Funktionen haben sehr kurze Namen und optional einen Zeilenabschluss (;). Welche Tipps und Tricks können Sie geben, um Code-Golf-Probleme in R zu lösen?


14
Die Antworten auf diese Frage könnten sich als Anti-Styleguide für R
erweisen, da Codegolf

Antworten:


44

Einige Hinweise:

  1. In R wird empfohlen, <-over zu verwenden =. Beim Golfen gilt das Gegenteil, da =es kürzer ist ...
  2. Wenn Sie eine Funktion mehrmals aufrufen, ist es oft sinnvoll, einen kurzen Alias ​​dafür zu definieren:

    as.numeric(x)+as.numeric(y)
    
    a=as.numeric;a(x)+a(y)
    
  3. Partial Matching kann Ihr Freund sein, insbesondere wenn Funktionen Listen zurückgeben, für die Sie nur ein Element benötigen. Vergleichen Sie rle(x)$lengthsmitrle(x)$l

  4. Bei vielen Herausforderungen müssen Sie Eingaben lesen. scanpasst oft gut dazu (der Benutzer beendet die Eingabe durch Eingabe einer Leerzeile).

    scan()    # reads numbers into a vector
    scan(,'') # reads strings into a vector
    
  5. Zwang kann nützlich sein. t=1ist viel kürzer als t=TRUE. Alternativ switchkönnen Sie auch wertvolle Zeichen speichern, aber Sie möchten 1,2 anstelle von 0,1 verwenden.

    if(length(x)) {} # TRUE if length != 0
    sum(x<3)         # Adds all the TRUE:s (count TRUE)
    
  6. Wenn eine Funktion etwas Kompliziertes berechnet und Sie verschiedene andere Arten von Berechnungen auf der Grundlage desselben Kernwerts benötigen, ist es häufig vorteilhaft, entweder: a) sie in kleinere Funktionen aufzuteilen, b) alle benötigten Ergebnisse als Liste zurückzugeben oder c) Lassen Sie es abhängig von einem Argument der Funktion verschiedene Arten von Werten zurückgeben.

  7. Wie in jeder Sprache, wissen Sie es gut - R hat Tausende von Funktionen, es gibt wahrscheinlich einige, die das Problem in sehr wenigen Zeichen lösen können - der Trick ist zu wissen, welche!

Einige obskure, aber nützliche Funktionen:

sequence
diff
rle
embed
gl # Like rep(seq(),each=...) but returns a factor

Einige eingebaute Datensätze und Symbole:

letters     # 'a','b','c'...
LETTERS     # 'A','B','C'...
month.abb   # 'Jan','Feb'...
month.name  # 'January','Feburary'...
T           # TRUE
F           # FALSE
pi          # 3.14...

22
  1. Anstatt ein Paket mit zu importieren library, greifen Sie mit auf die Variable aus dem Paket zu ::. Vergleichen Sie die folgenden Punkte:

    library(splancs);inout(...)
    splancs::inout(...)
    

    Natürlich ist es nur gültig, wenn eine einzelne Funktion aus dem Paket verwendet wird.

  2. Dies ist trivial, aber eine Faustregel für die Verwendung von @ Tommys Trick, eine Funktion zu aliasen: Wenn Ihr Funktionsname eine Länge von mund eine Häufigkeit nhat, dann nur dann alias, wenn m*n > m+n+3(weil Sie beim Definieren des Alias, den Sie ausgeben, m+3und dann immer noch ausgeben) 1 jedes Mal, wenn der Alias ​​verwendet wird). Ein Beispiel:

    nrow(a)+nrow(b)     # 4*2 < 4+3+2
    n=nrow;n(a)+n(b)
    length(a)+length(b) # 6*2 > 6+3+2
    l=length;l(a)+l(b)
    
  3. Zwang als Nebenwirkung von Funktionen:

    • Anstatt as.integerZeichenfolgen zu verwenden, können sie mit den folgenden Methoden in Ganzzahlen umgewandelt werden ::

      as.integer("19")
      ("19":1)[1] #Shorter version using force coercion.
      
    • Ganzzahlen, Zahlen usw. können auf ähnliche Weise zu Zeichen gezwungen werden, indem Folgendes verwendet pastewird as.character:

      as.character(19)
      paste(19) #Shorter version using force coercion.
      

6
Betreff: 3. Tipp, el("19":1)ist noch kürzer um ein Byte.
JayCe

19

Einige sehr spezielle Golftipps:

  • wenn Sie die Länge eines Vektors extrahieren müssen, sum(x|1)ist kürzer als length(x)solange xnumerisch ist, integer, komplex oder logisch.
  • Wenn Sie das letzte Element eines Vektors extrahieren müssen, ist es möglicherweise billiger (wenn möglich), den Vektor rückwärts zu initialisieren, indem Sie rev()und dann aufrufen, x[1]anstatt x[length(x)](oder mit dem obigen Tipp x[sum(x|1)]) (oder tail(x,1)- danke, Giuseppe!). Eine leichte Abwandlung dieses kann (wobei der vorletzte Element wurde gewünscht) zu sehen ist hier . Auch wenn Sie den Vektor nicht rückwärts initialisieren können, rev(x)[1]ist er immer noch kürzer als x[sum(x|1)](und funktioniert auch für Zeichenvektoren). Manchmal braucht revman zum Beispiel nicht n:1statt 1:n.
  • (Wie hier zu sehen ). Wenn Sie einen Datenrahmen in eine Matrix umwandeln möchten, verwenden Sie nicht as.matrix(x). Nehmen Sie die Transponierte der Transponierten t(t(x)).

  • ifist eine formale Funktion. Zum Beispiel "if"(x<y,2,3)ist kürzer als if(x<y)2 else 3(obwohl natürlich 3-(x<y)kürzer als beide). Dadurch werden nur Zeichen gespeichert, wenn Sie keine zusätzlichen geschweiften Klammern benötigen, um dies so zu formulieren, wie Sie es häufig tun.

  • Zum Testen der Ungleichheit von numerischen Objekten if(x-y)ist kürzer als if(x!=y). Alle numerischen Zeichen ungleich Null gelten als TRUE. Wenn Sie beispielsweise die Gleichstellung testen, if(x==y)a else bversuchen Sie es if(x-y)b else astattdessen. Siehe auch den vorherigen Punkt.

  • Diese Funktion elist nützlich, wenn Sie ein Element aus einer Liste extrahieren müssen. Das häufigste Beispiel ist wahrscheinlich strsplit: el(strsplit(x,""))Ist ein Byte weniger als strsplit(x,"")[[1]].

  • (Wie hier verwendet ) Mit der Vektorerweiterung können Sie Zeichen speichern: Wenn der Vektor veine Länge nhat, können Sie ihn v[n+1]ohne Fehler zuweisen . Zum Beispiel, wenn Sie die ersten zehn factorials drucken wollen könnten Sie tun: v=1;for(i in 2:10)v[i]=v[i-1]*ieher als v=1:10:for(...)(wenn auch wie immer, gibt es eine andere, besser, Art und Weise: cumprod(1:10))

  • Bei textbasierten Herausforderungen (insbesondere bei 2D-Herausforderungen) ist plotder Text manchmal einfacher als der Text cat. Das Argument pch=für plotsteuert, welche Zeichen gezeichnet werden. Dies kann verkürzt werden pc=(was auch eine Warnung gibt), um ein Byte zu speichern. Beispiel hier .

  • Verwenden Sie nicht, um das Wort einer Zahl zu ergreifen floor(x). Verwenden Sie x%/%1stattdessen.

  • Um zu testen, ob die Elemente eines numerischen oder ganzzahligen Vektors alle gleich sind, können Sie häufig sdanstelle von etwas Ausführlichem wie verwenden all.equal. Wenn alle Elemente gleich sind, ist ihre Standardabweichung Null ( FALSE), andernfalls ist die Standardabweichung positiv ( TRUE). Beispiel hier .

  • Einige Funktionen, von denen Sie erwarten würden, dass sie eine Ganzzahleingabe erfordern, funktionieren tatsächlich nicht. Beispielsweise seq(3.5)wird zurückgegeben 1 2 3(dasselbe gilt für den :Operator). Dies kann Anrufe vermeiden floorund bedeutet manchmal, dass Sie /anstelle von verwenden können %/%.


1
tail(v,1)ist genauso lang wie rev(v)[1]das "letzte Element eines Arrays".
Giuseppe

read.csv(t="a,b,c",,F)ist kürzer als el(strsplit("a,b,c",",")).
J.Doe

18
  1. Missbrauch der eingebauten Tund F. Standardmäßig werden sie in TRUEund ausgewertet FALSE, was automatisch in numerische Werte 1und umgewandelt werden kann 0, und sie können nach Belieben neu definiert werden. Dies bedeutet, dass Sie keinen Zähler initialisieren müssen (z. B. i=0... i=i+1). Sie können einfach Toder Fnach Bedarf verwenden (und direkt zu einem F=F+1späteren Zeitpunkt springen ).
  2. Denken Sie daran, dass Funktionen das zuletzt aufgerufene Objekt zurückgeben und keinen expliziten return()Aufruf benötigen .
  3. Das Definieren kurzer Aliase für häufig verwendete Funktionen ist sehr hilfreich, z p=paste. Wenn Sie eine Funktion häufig und mit genau zwei Argumenten verwenden, können Sie durch einen Alias- Zusatz einige Bytes einsparen. Das Einfügen von Aliasen muss von umgeben sein %. Zum Beispiel:

    `%p%`=paste

    Und anschließend x%p%yist das 1 Byte kürzer als p(x,y). Die Aliasdefinition für das Hinzufügen von Inhalten ist 4 Byte länger als die Definition für das Nicht-Hinzufügen. p=pasteSie müssen also sicherstellen, dass es sich lohnt.


9
Sie können primitive Funktionen verwenden und viele Bytes speichern:`+`=paste; x+y
Masclins

14

Unter Verwendung if, ifelseund`if`

Es gibt verschiedene Möglichkeiten, if-Anweisungen in R. Golf zu machen. Optimale Lösungen können sehr unterschiedlich sein.

Die Grundlagen

  1. ifist für den Kontrollfluss. Es ist nicht vektorisiert, dh es kann nur Bedingungen der Länge 1 auswerten. Es muss else(optional) ein else-Wert zurückgegeben werden.
  2. ifelseist eine Funktion. Es ist vektorisiert und kann Werte beliebiger Länge zurückgeben. Das dritte Argument (der else-Wert) ist obligatorisch. *
  3. `if`ist eine Funktion mit der gleichen Syntax wie ifelse. Es ist weder vektorisiert noch eines der Rückgabeargumente obligatorisch.

* Es ist technisch nicht obligatorisch; ifelse(TRUE,x)Funktioniert einwandfrei, aber es wird ein Fehler ausgegeben, wenn das dritte Argument leer ist und die Bedingung den Wert 0 ergibt FALSE. Die Verwendung ist also nur dann sicher, wenn Sie sicher sind, dass die Bedingung immer vorliegt TRUE, und wenn dies der Fall ist, warum beschäftigen Sie sich dann überhaupt mit einer if-Anweisung?

Beispiele

Diese sind alle gleichwertig:

if(x)y else z # 13 bytes
ifelse(x,y,z) # 13 bytes
`if`(x,y,z)   # 11 bytes

Beachten Sie, dass die Leerzeichen elsenicht erforderlich sind, wenn Sie Zeichenfolgen direkt im Code verwenden:

if(x)"foo"else"bar"   # 19 bytes
ifelse(x,"foo","bar") # 21 bytes
`if`(x,"foo","bar")   # 19 bytes

Bisher `if`scheint es der Gewinner zu sein, solange wir keine vektorisierten Eingaben haben. Aber was ist mit Fällen, in denen uns der Zustand else egal ist? Angenommen, wir möchten nur Code ausführen, wenn die Bedingung erfüllt ist TRUE. Für eine Codezeile ifist in der Regel Folgendes am besten:

if(x)z=f(y)         # 11 bytes
ifelse(x,z<-f(y),0) # 19 bytes
`if`(x,z<-f(y))     # 15 bytes

Bei mehreren Codezeilen ifist immer noch der Gewinner:

if(x){z=f(y);a=g(y)}        # 20 bytes
ifelse(x,{z=f(y);a=g(y)},0) # 27 bytes
`if`(x,{z=f(y);a=g(y)})     # 23 bytes

Es gibt auch die Möglichkeit, dass wir uns um die else-Bedingung kümmern und beliebigen Code ausführen möchten, anstatt einen Wert zurückzugeben. In diesen Fällen sind ifund `if`in der Byteanzahl äquivalent.

if(x)a=b else z=b   # 17 bytes
ifelse(x,a<-b,z<-b) # 19 bytes
`if`(x,a<-b,z<-b)   # 17 bytes

if(x){z=y;a=b}else z=b   # 22 bytes
ifelse(x,{z=y;a=b},z<-b) # 24 bytes
`if`(x,{z=y;a=b},z<-b)   # 22 bytes

if(x)a=b else{z=b;a=y}   # 22 bytes
ifelse(x,a<-b,{z=b;a=y}) # 24 bytes
`if`(x,a<-b,{z=b;a=y})   # 22 bytes

if(x){z=y;a=b}else{z=b;a=y}   # 27 bytes
ifelse(x,{z=y;a=b},{z=b;a=y}) # 29 bytes
`if`(x,{z=y;a=b},{z=b;a=y})   # 27 bytes

Zusammenfassung

  1. Verwenden ifelseSie diese Option, wenn Sie eine Länge> 1 eingegeben haben.

  2. Wenn Sie einen einfachen Wert sind Rückkehr anstatt viele Zeilen Code ausgeführt wird , die unter Verwendung von `if`Funktion ist wahrscheinlich kürzer als eine vollständige if... elseAussage.

  3. Wenn Sie nur einen einzigen Wert möchten TRUE, verwenden Sie if.

  4. Zur Ausführung von beliebigem Code, `if`und ifsind in der Regel die gleichen in Bezug auf die Anzahl der Bytes; Ich empfehle vor ifallem, weil es einfacher zu lesen ist.


1
Nett! Sehr gute Vergleiche, +1!
Billywob

13
  1. Sie können der aktuellen Umgebung eine Variable zuweisen und sie gleichzeitig als Argument für eine Funktion bereitstellen:

    sum(x <- 4, y <- 5)
    x
    y
  2. Wenn Sie a untergliedern data.frameund Ihre Bedingung von mehreren Spalten abhängt, können Sie vermeiden, dass der data.frameName wiederholt wird, indem Sie with(oder subset) verwenden.

    d <- data.frame(a=letters[1:3], b=1:3, c=4:6, e=7:9)
    with(d, d[a=='b' & b==2 & c==5 & e==8,])

    Anstatt von

    d[d$a=='b' & d$b==2 & d$c==5 & d$e==8,]

    Das spart natürlich nur Zeichen, wenn die Länge Ihrer Verweise auf die data.framedie Länge von überschreitetwith(,)

  3. if...elseblocks kann den Wert der finalen Anweisung zurückgeben, in der immer ein Teil des Blocks ausgeführt wird. Zum Beispiel anstelle von

    a <- 3
    if (a==1) y<-1 else
    if (a==2) y<-2 else y<-3

    Du kannst schreiben

    y <- if (a==1) 1 else 
         if (a==2) 2 else 3

4
Bei (1) ist nur Vorsicht geboten, wenn Sie dies tun, übergeben Sie es in der angegebenen Reihenfolge und nicht mit benannten Argumenten. Wenn f <- function(a,b) cat(a,b), dann f(a <- 'A', b <- 'B')ist das nicht dasselbe wie f(b <- 'B', a <- 'A').
Ari B. Friedman

11

Implizite Typkonvertierung

Die Funktionen as.character, as.numericund as.logicalsind zu bytelastig. Kürzen wir sie.

Umwandlung von numerisch nach logisch (4 Bytes)

Angenommen, es xhandelt sich um einen numerischen Vektor. Durch die Verwendung des Operators "Logisch nicht" wird die !Zahl implizit in einen logischen Vektor umgewandelt, wobei die Werte 0is FALSEund ungleich null sind TRUE. !dann invertiert das.

x=!x

x=0:3;x=!xkehrt zurück TRUE FALSE FALSE FALSE.

Umwandlung in Zeichen von numerisch oder logisch (7 Bytes)

Das macht Spaß. (Aus diesem Tweet .)

x[0]=''

R sieht, dass Sie den Vektor xmit aktualisieren '', der von Klasse ist character. Es wird also xin eine Klasse umgewandelt, charactersodass es mit dem neuen Datenpunkt kompatibel ist. Als nächstes geht es setzen ''an der richtigen Stelle ... aber der Index 0existiert nicht (dieser Trick funktioniert auch mit Inf, NaN, NA, NULL, und so weiter). Infolgedessen xwird nur in der Klasse geändert.

x=1:3;x[0]=''kehrt zurück "1" "2" "3"und x=c(TRUE,FALSE);x[0]=''kehrt zurück "TRUE" "FALSE".

Wenn in Ihrem Arbeitsbereich bereits ein Zeichenobjekt definiert ist, können Sie dieses verwenden, ''um ein Byte zu speichern. ZB x[0]=y!

Umwandlung in Zeichen von numerisch oder logisch unter bestimmten Bedingungen (6 Bytes)

J.Doe wies in den Kommentaren auf eine Sechs-Byte-Lösung hin:

c(x,"")

Dies funktioniert, wenn xes sich um eine atomare Funktion handelt und Sie diese an eine Funktion übergeben möchten, für die ein atomarer Vektor erforderlich ist. (Die Funktion kann eine Warnung über das Ignorieren von Elementen des Arguments auslösen.)

Umstellung auf numerisch von logisch (4 Bytes)

Sie können den funky Indexing-Trick von oben verwenden (z. B. x[0]=3), aber es gibt tatsächlich einen schnelleren Weg:

x=+x

Der positive Operator neu gefasst implizit den Vektor als numerischer Vektor, so TRUE FALSEwird 1 0.


Ihr letzter Trick könnte sein x=+x, TRUEals zu halten 1.
Giuseppe

@ Giuseppe Oh, duh, natürlich! Danke, jetzt aktualisiert.
Rturnbull

Umwandlung von numerisch oder logisch in Zeichen. Sie können c(x,"")if xis atomic verwenden, vorausgesetzt, Sie werden es xin einer Funktion verwenden, die sich nur um das erste Element kümmert (es kann sich beschweren). Dies ist 1 Byte billiger als x[0]="";.
J.Doe

10

Do-while-Schleifen in R

Gelegentlich wünsche ich mir, R hätte eine do-whileSchleife, weil:

 some_code
while(condition){
 some_code # repeated
}

ist viel zu lang und sehr ungolfen. Wir können dieses Verhalten jedoch wiederherstellen und einige Bytes mit der Leistungsfähigkeit der {Funktion entfernen.

{und (sind jeweils .PrimitiveFunktionen in R.

Die Dokumentation für sie lautet:

Effektiv (ist semantisch gleichbedeutend mit der Identität function(x) x, während {es etwas interessanter ist, siehe Beispiele.

und unter Wert,

Für (das Ergebnis der Auswertung des Arguments. Bei dieser Option ist die Sichtbarkeit festgelegt. Bei Verwendung auf oberster Ebene wird automatisch gedruckt.

Für {, das Ergebnis des letzten Ausdrucks ausgewertet . Dies hat die Sichtbarkeit der letzten Auswertung.

(Betonung hinzugefügt)

Also, was bedeutet das? Dies bedeutet, dass eine Do-While-Schleife so einfach ist wie

while({some_code;condition})0

weil die in Ausdrücken {}jeder ausgewertet sind, und nur die letzte durch zurückgegeben {, so dass wir bewerten some_codevor dem Eintritt in die Schleife, und es läuft jedes Mal conditionist TRUE(oder truthy). Dies 0ist einer der vielen 1-Byte-Ausdrücke, die den "echten" Körper der whileSchleife bilden.


10
  1. Missbrauch outer, um eine beliebige Funktion auf alle Kombinationen von zwei Listen anzuwenden. Stellen Sie sich eine Matrix mit i, j vor, die durch die ersten Argumente indiziert wird. Dann können Sie für jedes Paar eine beliebige Funktion (i, j) definieren.

  2. Verwenden Sie Mapals Abkürzung für mapply. Mein Anspruch ist, dass mapplyes in Situationen, in denen Sie auf den Index zugreifen müssen, billiger ist als eine for-Schleife. Missbrauch der Listenstruktur in R. unlistist teuer. methods::elDamit können Sie das erste Element kostengünstig aus der Liste entfernen. Versuchen Sie, Funktionen mit Listenunterstützung nativ zu verwenden.

  3. Verwenden Sie do.calldiese Option, um Funktionsaufrufe mit beliebigen Eingaben zu verallgemeinern.

  4. Das Akkumulieren von Argumenten Reduceist äußerst hilfreich für Code-Golf.

  5. Schreiben auf die Konsole Zeile für Zeile mit cat(blah, "\n")ist billiger mit write(blah, 1). Fest codierte Zeichenfolgen mit "\ n" sind in manchen Situationen möglicherweise billiger.

  6. Wenn eine Funktion mit Standardargumenten geliefert wird, können Sie mit der Funktion (,, n-arg) das n-te Argument direkt angeben. Beispiel: seq(1, 10, , 101)In einigen Funktionen wird ein partieller Argumentvergleich unterstützt. Beispiel: seq(1, 10, l = 101).

  7. Wenn Sie eine Herausforderung mit der Manipulation von Zeichenfolgen sehen, drücken Sie einfach die Zurück-Taste und lesen Sie die nächste Frage. strsplitist alleinstehend für die Zerstörung des R-Golfs verantwortlich.

Nun zu einigen neu entdeckten Tipps aus dem Jahr 2018

  1. A[cbind(i,j)] = zkann ein guter Weg sein, um Matrizen zu manipulieren. Diese Operation ist sehr byteeffizient, vorausgesetzt, Sie entwerfen i, j, zVektoren mit der richtigen Länge. Sie können noch mehr sparen, indem Sie die eigentliche Index- / Zuweisungsfunktion aufrufen "[<-"(cbind(i,j), z). Diese Art des Aufrufs gibt die geänderte Matrix zurück.

  2. Verwenden Sie eine neue Zeile anstelle von \nZeilenumbrüchen.

  3. Wenn Sie die Anzahl der Zeilen verringern, können Sie Byte sparen. Inline-Zuweisung lapply(A<-1:10,function(y) blah)und Zuweisung von Funktionsargumenten function(X, U = X^2, V = X^3)sind Möglichkeiten, dies zu tun.

  4. Ist "[<-"so eine Funktion in R (und hängt mit meiner alten Frage auf SO zusammen )! Das ist die zugrunde liegende Funktion, die für Operationen wie x[1:5] = rnorm(5). Mit der netten Eigenschaft, die Funktion nach Namen aufzurufen, können Sie den geänderten Vektor zurückgeben. In order words "[<-"(x, 1:5, normr(5))funktioniert fast genauso wie der obige Code, außer dass das geänderte x zurückgegeben wird. Die zugehörigen Werte für "length <-", "names <-" und "anything <-" geben alle eine geänderte Ausgabe zurück


1
Ich denke, die Verwendung "[<-"verdient eine eigene "Tipps" -Antwort, da sie das geänderte Array / die geänderte Matrix / was auch immer zurückgibt.
Giuseppe

10
  1. Werte in der Zeile speichern : Andere haben erwähnt, dass Sie Werte der Reihe nach übergeben und zur Verwendung an anderer Stelle zuweisen können, z

    sum(x<- 1:10, y<- seq(10,1,2))

    Sie können jedoch auch Werte inline speichern , um sie in derselben Zeile zu verwenden !

    Zum Beispiel

    n=scan();(x=1:n)[abs(x-n/2)<4]

    Liest aus stdin, erstellt eine Variable x=1:nund indiziert dann xmit dem Wert von x. Dies kann manchmal Bytes sparen.

  2. Alias ​​für den leeren Vektor Sie können ihn {}als leeren Vektor verwenden, c()da beide zurückkehren NULL.

  3. Basis - Konvertierung Für ganzzahlige Ziffern nin der Basis 10, verwenden n%/%10^(0:nchar(n))%%10. Dies hinterlässt eine nachgestellte Null. Wenn dies für Sie wichtig ist, verwenden Sie diese, n%/%10^(1:nchar(n)-1)%%10da sie kürzer als die Array-Indizierung ist. Dies kann floor(log(n,b))+1anstelle von an andere Basen angepasst werdennchar(n)

  4. Verwenden von seqund: : Anstatt 1:length(l)(oder 1:sum(x|1)) zu verwenden, können Sie verwenden seq(l), solange la listoder eine vectorLänge größer als 1 hat, wie dies standardmäßig der Fall ist seq_along(l). Wenn lmöglicherweise Länge sein könnte 1, seq(a=l)wird der Trick.

    Zusätzlich :wird (mit einer Warnung) das erste Element seiner Argumente verwendet.

  5. Entfernen von Attributen Mit c()einem array(oder matrix) wird dasselbe getan wie mit as.vector; Im Allgemeinen werden Nicht-Namensattribute entfernt.

  6. Factorial Using gamma(n+1)ist kürzer als using factorial(n)und factorialwird als gamma(n+1)ohnehin definiert .

  7. Coin Flipping Wenn Sie eine zufällige Aufgabe in 50% der Fälle ausführen müssen, ist using rt(1,1)<0kürzer als runif(1)<0.5drei Bytes.

  8. Elemente extrahieren / ausschließen head und tailsind oft nützlich, um die ersten / letzten Elemente eines Arrays zu extrahieren. head(x,-1)extrahiert alle Elemente mit Ausnahme des letzten Elements und ist kürzer als die Verwendung der negativen Indizierung, wenn Sie die Länge noch nicht kennen:

    head(x,-1)
    x[-length(x)]
    x[-sum(x|1)]


@ J.Doe verdient einen eigenen Beitrag, denke ich! Vielleicht mit dem Titel "Alternativen zu rep". Bei anderen Fragen zu Tipps gilt eine Beschränkung von einem Tipp pro Antwort, was ich auch bei dieser Frage voll und ganz unterstütze! Außerdem 1:n*0ist es kürzer als Im(1:n)zwei Bytes, was bedeutet, dass Ihr zweiter Stich auch sein kann x+0*-n:n:-)
Giuseppe

1
@ J.Doe Oder noch besser, !1:nist auch ein Array von nNullen je nach Anwendungsfall; Wir danken jedoch der MATL / MATLAB-Tippfrage (wahrscheinlich Luis Mendo) für diese Frage.
Giuseppe

Vielen Dank, @ Giuseppe! Darf ich vorschlagen, dass Sie diesen Beitrag erstellen, da ich Ihren guten Ideen keinen Ruf entziehen möchte?
J.Doe

@ J.Doe oh, das macht mir nichts aus. Es ist immer gut, wenn andere R-Golfer mehr Sichtbarkeit erhalten. Ich denke, es ist fair zu sagen, dass ich zu diesem Zeitpunkt ein ziemlich bekanntes Wesen bin! Sie haben ziemlich beeindruckende Verbesserungen vorgeschlagen, nehmen Sie also den Sprecher (Wortspiel nicht beabsichtigt) und machen Sie weiter mit der guten Arbeit beim Golfen :-)
Giuseppe

1
nicht (log(i,b)%/%1):0)statt floor(log(n,b))+1?
Nur ASCII

8

Einige grundlegende Konzepte sollten aber etwas nützlich sein:

  1. In Kontrollflussanweisungen können Sie missbrauchen, dass jede Zahl ungleich Null als ausgewertet wird TRUE, z. B .: if(x)entspricht if(x!=0). Umgekehrt if(!x)ist gleichbedeutend mit if(x==0).

  2. Bei der Generierung von Sequenzen mit :(zB 1:5) kann man die Tatsache missbrauchen, dass der Exponentiationsoperator ^der einzige Operator ist, der Vorrang vor dem :Operator hat (im Gegensatz zu +-*/).

    1:2^2 => 1 2 3 4 

    Dies erspart Ihnen zwei Bytes in den Klammern, die Sie normalerweise verwenden müssten, wenn Sie z. B. über die Elemente einer n x nMatrix ( 1:n^2) oder einer anderen Ganzzahl, die mit der Exponentialschreibweise ( 1:10^6) kürzer ausgedrückt werden kann, eine Schleife ausführen möchten .

  3. Ein verwandter Trick kann natürlich auch für vektorisierte Operationen verwendet werden +-*/, obwohl er am häufigsten für Folgendes gilt +-:

    for(i in 1:(n+1)) can instead be written as for(i in 0:n+1)

    Dies funktioniert, weil +1vektorisiert und 1zu jedem Element des 0:nVektors addiert wird 1 2 ... n+1. Ebenso 0:(n+1) == -1:n+1spart man auch ein Byte.

  4. Wenn Sie kurze Funktionen schreiben (die in einer Zeile ausgedrückt werden können), können Sie die Variablenzuweisung missbrauchen, um zwei Bytes in den geschweiften Klammern zu speichern {...}:

    f=function(n,l=length(n))for(i in 1:l)cat(i*l,"\n")
    f=function(n){l=length(n);for(i in 1:l)cat(i*l,"\n")}

    Beachten Sie, dass dies möglicherweise nicht immer den Regeln bestimmter Herausforderungen entspricht.


Nur eine kleine Korrektur: ^ist vektorisiert, es ist nur so, dass es Vorrang hat :(dh es wird vorher ausgeführt, es :sei denn, Klammern zeigen ausdrücklich das Gegenteil an, siehe ?Syntaxfür die genaue Rangfolge von binären und unären Operatoren). Gleiches gilt für die Binärdatei, +-/*die eine niedrigere Priorität hat als :Ihr Trick Nr. 3.
Plannapus

@plannapus Danke für die Klarstellung. Wortlaut aktualisiert.
Billywob

7

Ändern Sie die Bedeutung von Operatoren

R-Operatoren sind nur Funktionen, die vom Parser speziell behandelt werden. Zum Beispiel <ist eigentlich eine Funktion von zwei Variablen. Diese beiden Codezeilen machen dasselbe:

x < 3
`<`(x, 3) 

Sie können einem Operator eine andere Funktion zuweisen, und der Parser erledigt dies weiterhin, einschließlich der Beachtung der Operatorpriorität. Der letzte Funktionsaufruf ist jedoch der neue und nicht der ursprüngliche. Zum Beispiel:

`<`=rep

Das bedeutet nun, dass diese beiden Codezeilen dasselbe tun:

rep("a", 3)
"a"<3

und Vorrang wird respektiert, was zu Dingen wie führt

"a"<3+2
#[1] "a" "a" "a" "a" "a"

Siehe zum Beispiel diese Antwort und auch die Seite mit der Rangfolge der Operatoren . Als Nebeneffekt wird Ihr Code so kryptisch wie einer, der in einer Golfsprache geschrieben ist.

Einige Operatoren mögen +und -akzeptieren entweder einen oder zwei Parameter, so dass Sie sogar Folgendes tun können:

`-`=sample
set.seed(1)
-5  # means sample(5)
#[1] 2 5 4 3 1
5-2 # means sample(5, 2)
#[1] 5 4

Siehe zum Beispiel diese Antwort .

Siehe auch diese Antwort zur Verwendung [als Zwei-Byte-Operator mit drei Argumenten.


2
Dies ist ein Kommentar zu den Tipps von rturnbull, aber ich denke, wir müssen damit beginnen, eine Regel "Ein Tipp pro Antwort" durchzusetzen, weil es so verdammt schwer ist, den zu finden, den ich brauche, wenn ich hierher komme.
Giuseppe

1
Abhängig von der Rangfolge der Operatoren können Sie auch einige Dinge tun, die möglicherweise hilfreich sind. like <hat eine niedrigere Priorität als +, aber *eine höhere Priorität als, +so dass Sie sie möglicherweise miteinander verketten können!
Giuseppe

1
@ Giuseppe Du weißt, was ich vor dem Posten gesucht habe und nicht finden konnte. Vielen Dank für den Hinweis. Ich plane, mehr Details zur Operatorrangfolge mit Beispielen hinzuzufügen, da ich diesen Trick immer häufiger verwende.
JayCe

2
Hier ist ein Spaß: Wenn Sie binden ?an pasteoder eine andere Funktion , die zwei Argumente nehmen, die Rangfolge bedeutet , dass Sie immer noch Inline - Zuweisungen über nutzen können a<-b?d<-e.
J.Doe

1
Sie sollten [einen Alias ​​mit drei Elementen hinzufügen (das sind zwei Bytes). Ich finde es oft hilfreich für Dinge wie outer(und vergesse es immer wieder!), Obwohl Sie natürlich sicherstellen müssen, dass Sie es nicht wirklich brauchen [. Es ist wahrscheinlich auch hilfreich, einen Link zur Operator-Prioritätsseite zu erstellen, um die Auswahl des Alias ​​zu erleichtern.
Giuseppe

5

Szenarien, in denen Sie paste(...,collapse="")und vermeiden könnenstrsplit

Dies ist ein Schmerz bei den üblichen Saitenproblemen. Es gibt einige Problemumgehungen.

  • Reduce(paste0,letters) für -5 Bytes von paste0(letters,collapse="")

  • Ein 2-Byte-Golf, bei dem Sie eine Liste mit zwei Vektoren haben c(1,2,3)und c(4,5,6)diese elementweise zu einer Zeichenfolge verketten möchten "142536". Betreibermissbrauch gibt Ihnen p=paste0;"^"=Reduce;p^p^rdie Möglichkeit, beim normalen paste0Anruf zwei Bytes zu sparen .

  • Anstatt paste0("(.{",n,"})")zB einen regulären Ausdruck für 20 Bytes zu konstruieren, betrachten Sie einen regulären Ausdruck in einem regulären Ausdruck: sub(0,"(.{0})",n)für 17 Bytes.

Manchmal (eigentlich ziemlich oft) müssen Sie einen Vektor von Zeichen oder Zeichenketten durchlaufen oder ein Wort in Buchstaben aufteilen. Es gibt zwei häufige Anwendungsfälle: Zum einen müssen Sie einen Vektor von Zeichen als Eingabe für eine Funktion oder ein Programm verwenden, und zum anderen kennen Sie den Vektor im Voraus und müssen ihn irgendwo in Ihrem Code speichern.

ein. Wo müssen Sie eine Zeichenfolge als Eingabe nehmen und es in Wörter oder Zeichen aufteilen .

  1. Wenn Sie Wörter benötigen (einschließlich Zeichen als Sonderfall):

    • Wenn ein Zeilenvorschub 0x10(ASCII 16), der die Wörter trennt, in Ordnung ist, x=scan(,"")wird der Code vorgezogen function(s,x=el(strsplit(s," "))).

    • Wenn kann die Worte von getrennt werden jedes andere Leerzeichen , einschließlich mehrerer Leerzeichen, Tabulatoren, Zeilenumbrüche usw., können Sie @ ngm die Verwendung Double Scan Trick : x=scan(,"",t=scan(,"")). Dies gibt den eingelesenen String scanals textArgument an und trennt ihn durch Leerzeichen.

    • Das zweite Argument in scankann eine beliebige Zeichenfolge sein. Wenn Sie also eine erstellt haben, können Sie diese recyceln , um ein Byte zu speichern.

  2. Wenn Sie eine Eingabezeichenfolge in einen Zeichenvektor umwandeln müssen :

    • x=el(strsplit(s,""))ist die kürzeste allgemeine Lösung. Das splitArgument funktioniert auf etwas mit der Länge Null einschließlich c(), {}usw. Wenn Sie also eine Länge von Null Variable erstellt passieren haben, können Sie es verwenden könnte ein Byte zu speichern.

    • Wenn Sie mit den ASCII-Zeichencodes arbeiten können, berücksichtigen Sie utf8ToInt, da utf8ToInt(x)kürzer als der strsplitAufruf ist. Das Zusammenfügen intToutf8(utf8ToInt(x))ist kürzer als Reduce(paste0,el(strsplit(x,""))).

    • Wenn Sie beliebige Zahlenfolgen wie "31415926535"bei der Eingabe teilen müssen , können Sie utf8ToInt(s)-483 Bytes einsparen el(strsplit(s,"")), vorausgesetzt, Sie können anstelle der Zeichen, wie dies häufig der Fall ist, die ganzzahligen Ziffern verwenden. Dies ist auch kürzer als das übliche Rezept zum Aufteilen von Zahlen in Dezimalstellen.

b. Wo Sie einen festen Vektor von Wörtern oder Zeichen im Voraus benötigen .

  • Wenn Sie einen Vektor aus einzelnen Zeichen mit einem regelmäßigen Muster oder in alphabetischer Reihenfolge benötigen, sehen Sie sich die Verwendung intToUtf8oder chartrAnwendung auf eine Sequenz über a:boder auf die eingebauten Buchstabensätze lettersoder an LETTERS. Die eingebaute Mustersprache chartrist besonders mächtig .

  • Für 1 bis 3 Zeichen oder Worte , c("a","b","c")ist die einzige allgemeine kürzeste Lösung.

  • Wenn Sie einen festen Vektor müssen zwischen 4 und 10 nicht Leerzeichen oder Wörter , verwenden Sie scanmit stdinals filearg:

f(x=scan(,""))
q
w
e
r
t
y
u
  • Wenn scanaus stdinnicht möglich ist, für 6 oder mehr nicht Leerzeichen oder Wörter , verwenden Sie scanmit dem textArgument scan(,"",t="a b c d e f").

  • Wenn Sie einen Vektor aus (a) 6 oder mehr Zeichen eines beliebigen Typs oder (b) 10 oder mehr Nicht-Whitespace-Zeichen benötigen , ist strsplitvia x=el(strsplit("qwertyuiop",""))wahrscheinlich der richtige Weg.

  • Sie können der Lage sein , mit dem wegzukommen folgende Zitat Trick : quote(Q(W,E,R,T,Y)), was dieser Ausdruck schafft. Einige Funktionen mögen strrepund grepwerden dies zu einem Vektor von Zeichenketten zwingen! Wenn Sie dies tun, ist dies für eine beliebige Länge von Wort- oder Zeichenvektoren von 3 bis 11 geeignet.

  • Es gibt keinen guten Grund für die Verwendung strsplitvon Wörtern über x=el(strsplit("q w e r t y"," ")). Es verliert immer scan(,"",t="q w e r t y"))um einen festen Overhead von 5 Bytes.

Hier ist eine Tabelle der Byteanzahlen, die von jedem Ansatz zum Einlesen eines Vektors mit einzelnen Zeichen der Länge verwendet werden n. Die relative Reihenfolge innerhalb jeder Zeile gilt für Zeichen oder Worte, mit Ausnahme strsplitauf ""das funktioniert nur auf Zeichen.

| n  | c(...) | scan | scan | strsplit | quote |
|    |        |+stdin|+text | on ""    | hack  |
|    |        |      |      | CHAR ONLY|       |
|----|--------|------|------|----------|-------|
| 1  | 3      | 11   | 15   | 20       | 8     |
| 2  | 10     | 13   | 17   | 21       | 11    |
| 3  | 14     | 15   | 19   | 22       | 13    |
| 4  | 18     | 17   | 21   | 23       | 15    |
| 5  | 22     | 19   | 23   | 24       | 17    |
| 6  | 26     | 21   | 25   | 25       | 19    |
| 7  | 30     | 23   | 27   | 26       | 21    |
| 8  | 34     | 25   | 29   | 27       | 23    |
| 9  | 38     | 27   | 31   | 28       | 25    |
| 10 | 42     | 29   | 33   | 29       | 27    |
| 11 | 46     | 31   | 35   | 30       | 29    |
| 12 | 50     | 33   | 37   | 31       | 31    |

c. Wenn Sie Text als Zeichenmatrix eingeben müssen , sind einige Rezepte kurz

s="hello\nworld\n foo"

# 43 bytes, returns "" padded data frame
# If lines > 5 are longer than lines <= 5, wraps around and causes error
read.csv(t=gsub("(?<=.)(?=.)",",",s,,T),,F)

# 54 bytes with readLines(), "" padded matrix
sapply(p<-readLines(),substring,p<-1:max(nchar(p)),p))

# plyr not available on TIO
# 58 bytes, returns NA padded matrix, all words split by whitespace
plyr::rbind.fill.matrix(Map(t,strsplit(scan(,"",t=s),"")))
# 61 bytes, returns NA padded matrix
plyr::rbind.fill.matrix(Map(t,(a=strsplit)(el(a(s,"\n")),"")))

1
scanhat ein textArgument, das wettbewerbsfähiger ist, als el(strsplit(x," "))wenn Sie nur Zeichenfolgen benötigen! Probieren Sie es online! Im Gegensatz zu Ihrem letzten Vorschlag von read.csv.
Giuseppe

Wenn Sie nur Zeichen wollen, ist Ihr Anruf von scanbis zu 5 Zeichen besser, el(strsplit(x,""))ist wettbewerbsfähiger als scanfür 6 oder mehr. Probieren Sie es online! Ich habe noch keine gute Verwendung für gefunden read.csv, aber vielleicht wäre es nützlich, wenn Sie aus irgendeinem Grund eine Datentabelle benötigen würden?
J.Doe

Ich habe noch nie eine Verwendung für eine gefunden, data.frameaber vielleicht müssen wir eine Herausforderung finden / erstellen, wo es hilfreich wäre! Vielleicht ein dplyrStil group_by()und eine summarize()Art der Manipulation? IDK.
Giuseppe

Und zum Lesen in Streichern scan(,"")scheint das noch besser? Probieren Sie es online!
J.Doe

Ja sicher, obwohl wenn Sie ein Eingabeformat genau so interpretieren, wie es ngm hier tut, ist double scanpraktisch.
Giuseppe

4

Einige Möglichkeiten, um das erste Nicht-Null-Element eines Arrays zu finden.

Wenn es einen Namen hat x:

x[!!x][1]

Gibt zurück, NAwenn keine Elemente ungleich Null vorhanden sind (einschließlich wann xleer, aber nicht NULLwelche Fehler).

Anonym:

Find(c, c(0,0,0,1:3))

Gibt zurück, NULLwenn keine Elemente ungleich Null oder leer oder NULL.


Dies wird zurückgegeben, NAwenn alle Elemente von xNull sind, glaube ich.
Giuseppe

Find(c,x)ist dasselbe bytecount mit: dem Vorteil, dass Sie x nicht wiederholen (definieren) müssen, und einem anderen Verhalten, wenn keine Übereinstimmung vorliegt. TIO
JayCe

Findist auch ein bisschen sicherer, wenn es funktioniert NULL, solange nichts anderes mit dem Ergebnis geschehen muss. In diesem Fall bin ich mir nicht sicher, ob ich zurückkomme NAoder NULLsicherer bin .
ngm

Oh, das stimmt. das problem mit der rückgabe von null sind fehler ... bei der version vergleichsfrage habe ich zuerst probiert sign(Find(c,w))was fehler verursacht hat - musste machen Find(c,sign(w))um es nicht fehler zu machen . Ich denke, beide Wege haben ihren Nutzen.
JayCe

4

Alternativen zu rep()

rep()Mit dem Doppelpunktoperator :und dem Vektorrecycling von R kann dies manchmal vermieden werden .

  • Zum Wiederholen nNullen, wo n>0, 0*1:nist 3 Bytes kürzer als rep(0,n)und !1:nein Feld von FALSEist 4 Bytes kürzer, wenn der Anwendungsfall dies zulässt.

  • Um die x nZeiten zu wiederholen , x+!1:nist 2 Bytes kürzer als rep(x,n). nVerwenden !!1:nSie für diejenigen, wenn Sie ein Array von verwenden können TRUE.

  • Um es zu wiederholen x 2n+1Zeiten, wo n>=0, x+0*-n:nist 4 Byte kürzer als rep(x,2*n+1).

  • Die Aussage !-n:nwird TRUEvon beiden Seiten flankiert n FALSE. Dies kann verwendet werden , um eine gerade Anzahl von Zeichen in Aufrufen zu generieren , intToUtf8()wenn Sie daran denken, dass eine Null ignoriert wird.

Modulare Arithmetik kann nützlich sein. repAnweisungen mit dem eachArgument können manchmal mit einer Ganzzahldivision vermieden werden.

  • Um den Vektor zu generieren c(-1,-1,-1,0,0,0,1,1,1), -3:5%/%3ist 5 Bytes kürzer als rep(-1:1,e=3).

  • Um den Vektor zu erzeugen c(0,1,2,0,1,2,0,1,2), 0:8%%3speichert 4 Byte auf rep(0:2,3).

  • Manchmal können nichtlineare Transformationen die Sequenzarithmetik verkürzen. Zur Karte i in 1:15zu c(1,1,3,1,1,3,1,1,3,1,1,3,1,1,3)innerhalb einer zusammengesetzten Anweisung, die offensichtliche Golfy Antwort ist 1+2*(!i%%3)für 11 Bytes. Die Größe3/(i%%3+1) beträgt jedoch 10 Byte und entspricht der gleichen Sequenz. Sie kann daher verwendet werden, wenn Sie die Sequenz für die Array-Indizierung benötigen.


3

Wenn Sie eine Funktion verwenden müssen, verwenden Sie pryr::f()anstelle von function().

Beispiel:

function(x,y){x+y}

ist äquivalent zu

pryr::f(x,y,x+y)

oder noch besser

pryr::f(x+y)

Da Wenn es nur ein Argument gibt, werden die Formale aus dem Code erraten .


Es sei denn, Sie können es auf ein Argument beschränken (wie im dritten Beispiel), ist dies kein Golf, denn es function(x,y){x+y}kann geschrieben werden wie function(x,y)x+yfür denselben bytecount, pryr::f(x,y,x+y)aber mit besserer Lesbarkeit.
Khuldraeseth na'Barya

3

Überleben Herausforderungen mit Streichern

Wie in einer anderen Antwort erwähnt, unlist(strsplit(x,split="")und paste(...,collapse="")kann deprimierend sein. Aber gehen Sie nicht einfach davon weg, es gibt Workarounds!

  • utf8ToIntKonvertiert einen String in einen Vektor, intToUtf8führt die umgekehrte Operation durch. Sie erhalten einen Vektor von int, keinen Vektor von, charaber manchmal ist es das, wonach Sie suchen. Zum Beispiel, um eine Liste zu generieren -, die besser intToUtf8(rep(45,34))alspaste(rep("-",34),collapse="")
  • gsubist nützlicher als andere Funktionen der grepFamilie, wenn mit einer einzelnen Zeichenfolge gearbeitet wird. Die beiden obigen Ansätze können wie in dieser Antwort kombiniert werden , die vom Rat von ovs , Giuseppe und ngm profitiert hat .
  • Wählen Sie eine bequeme E / A - Format , wie in dieser Antwort Eingabe als Textzeilen unter (ohne Anführungszeichen) oder diesem einen Vektor von Zeichen nehmen. Wenden Sie sich im Zweifelsfall an das OP.
  • Wie in den Kommentaren erwähnt, werden <die Zeichenfolgen wie erwartet lexikografisch verglichen.

intToUtf8Es gibt auch ein zweites Argument, multiple = FALSEdas von ints in einzelne Zeichen (Zeichenfolgen mit der Länge eins) konvertiert, und nicht in eine einzelne Zeichenfolge, wenn es auf gesetzt ist TRUE.
Giuseppe

Ab 3.5.0 gibt es außerdem ein drittes Argument allow_surrogate_pairs = FALSE, aber ich weiß nicht, was es bewirkt. Die Docs sagen etwas über das Lesen von zwei Bytes als ein, UTF-16aber ich weiß kaum, was das UTF-8ist. Ich werde es einfach ignorieren, bis jemand anderes einen Weg findet, damit Golf zu spielen.
Giuseppe

2

Tipps für Probleme mit eingeschränkten Quellen:

  1. Zeichen in R-Literalkonstanten können durch Hex-Codes, Oktal-Codes und Unicodes ersetzt werden.

    zB kann der String "abcd"geschrieben werden:

        # in octal codes
        "\141\142\143\144"
    
        # in hex codes
        "\x61\x62\x63\x64"
    
        # in unicodes
         "\u61\u62\u63\u64"
        # or
        "\U61\U62\U63\U64" 

    Wir können auch Zeichen mit Oktal / Hex / Unicode mischen und einige Oktal-Codes und einige Hex-Codes zusammen verwenden, solange Unicode-Zeichen nicht mit Oktal / Hex gemischt werden, zB:

        # Valid
        "a\142\x63\x64"
    
        # Valid
        "ab\u63\U64"
    
        # Error: mixing Unicode and octal/hex escapes in a string is not allowed
        "\141\142\x63\u64"

    Weitere Einzelheiten finden Sie am Ende dieses Abschnitts .

  2. Da Funktionen mit String-Literalen geschrieben werden können, cat()kann zB alternativ geschrieben werden:

    'cat'()
    "cat"()
    `cat`()

    Wir können auch Oktalcodes, Hex-Codes und Unicode für Funktionsnamen verwenden:

    # all equal to cat()
    "\143\141\164"()
    `\x63\x61\x74`()
    '\u63\u61\u74'()
    "ca\u74"()

    mit der einzigen Ausnahme, dass Unicode-Sequenzen in Backticks `` nicht unterstützt werden

  3. Runde Klammern können den Missbrauch von Operatoren verhindern, zB:

    cat('hello')
    
    # can be written as
    `+`=cat;+'hello'

Eine Anwendung aller drei Tricks finden Sie in dieser Antwort


Zahlen können auch hexadezimal geschrieben werden: 0xBund 0xbzurückgegeben werden 11(Backticks oder Anführungszeichen sind nicht erforderlich).
Robin Ryder
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.