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?
58
Antworten:
Einige Hinweise:
<-
over zu verwenden=
. Beim Golfen gilt das Gegenteil, da=
es kürzer ist ...Wenn Sie eine Funktion mehrmals aufrufen, ist es oft sinnvoll, einen kurzen Alias dafür zu definieren:
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)$lengths
mitrle(x)$l
Bei vielen Herausforderungen müssen Sie Eingaben lesen.
scan
passt oft gut dazu (der Benutzer beendet die Eingabe durch Eingabe einer Leerzeile).Zwang kann nützlich sein.
t=1
ist viel kürzer alst=TRUE
. Alternativswitch
können Sie auch wertvolle Zeichen speichern, aber Sie möchten 1,2 anstelle von 0,1 verwenden.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.
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:
Einige eingebaute Datensätze und Symbole:
quelle
Anstatt ein Paket mit zu importieren
library
, greifen Sie mit auf die Variable aus dem Paket zu::
. Vergleichen Sie die folgenden Punkte:Natürlich ist es nur gültig, wenn eine einzelne Funktion aus dem Paket verwendet wird.
Dies ist trivial, aber eine Faustregel für die Verwendung von @ Tommys Trick, eine Funktion zu aliasen: Wenn Ihr Funktionsname eine Länge von
m
und eine Häufigkeitn
hat, dann nur dann alias, wennm*n > m+n+3
(weil Sie beim Definieren des Alias, den Sie ausgeben,m+3
und dann immer noch ausgeben) 1 jedes Mal, wenn der Alias verwendet wird). Ein Beispiel:Zwang als Nebenwirkung von Funktionen:
Anstatt
as.integer
Zeichenfolgen zu verwenden, können sie mit den folgenden Methoden in Ganzzahlen umgewandelt werden:
:Ganzzahlen, Zahlen usw. können auf ähnliche Weise zu Zeichen gezwungen werden, indem Folgendes verwendet
paste
wirdas.character
:quelle
el("19":1)
ist noch kürzer um ein Byte.Einige sehr spezielle Golftipps:
sum(x|1)
ist kürzer alslength(x)
solangex
numerisch ist, integer, komplex oder logisch.rev()
und dann aufrufen,x[1]
anstattx[length(x)]
(oder mit dem obigen Tippx[sum(x|1)]
) (odertail(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 alsx[sum(x|1)]
(und funktioniert auch für Zeichenvektoren). Manchmal brauchtrev
man zum Beispiel nichtn:1
statt1: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 Transponiertent(t(x))
.if
ist eine formale Funktion. Zum Beispiel"if"(x<y,2,3)
ist kürzer alsif(x<y)2 else 3
(obwohl natürlich3-(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 alsif(x!=y)
. Alle numerischen Zeichen ungleich Null gelten alsTRUE
. Wenn Sie beispielsweise die Gleichstellung testen,if(x==y)a else b
versuchen Sie esif(x-y)b else a
stattdessen. Siehe auch den vorherigen Punkt.Diese Funktion
el
ist nützlich, wenn Sie ein Element aus einer Liste extrahieren müssen. Das häufigste Beispiel ist wahrscheinlichstrsplit
:el(strsplit(x,""))
Ist ein Byte weniger alsstrsplit(x,"")[[1]]
.(Wie hier verwendet ) Mit der Vektorerweiterung können Sie Zeichen speichern: Wenn der Vektor
v
eine Längen
hat, können Sie ihnv[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]*i
eher alsv=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
plot
der Text manchmal einfacher als der Textcat
. Das Argumentpch=
fürplot
steuert, welche Zeichen gezeichnet werden. Dies kann verkürzt werdenpc=
(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 Siex%/%1
stattdessen.Um zu testen, ob die Elemente eines numerischen oder ganzzahligen Vektors alle gleich sind, können Sie häufig
sd
anstelle von etwas Ausführlichem wie verwendenall.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ückgegeben1 2 3
(dasselbe gilt für den:
Operator). Dies kann Anrufe vermeidenfloor
und bedeutet manchmal, dass Sie/
anstelle von verwenden können%/%
.quelle
tail(v,1)
ist genauso lang wierev(v)[1]
das "letzte Element eines Arrays".read.csv(t="a,b,c",,F)
ist kürzer alsel(strsplit("a,b,c",","))
.T
undF
. Standardmäßig werden sie inTRUE
und ausgewertetFALSE
, was automatisch in numerische Werte1
und umgewandelt werden kann0
, 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 einfachT
oderF
nach Bedarf verwenden (und direkt zu einemF=F+1
späteren Zeitpunkt springen ).return()
Aufruf benötigen .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:Und anschließend
x%p%y
ist das 1 Byte kürzer alsp(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=paste
Sie müssen also sicherstellen, dass es sich lohnt.quelle
`+`=paste; x+y
Unter Verwendung
if
,ifelse
und`if`
Es gibt verschiedene Möglichkeiten, if-Anweisungen in R. Golf zu machen. Optimale Lösungen können sehr unterschiedlich sein.
Die Grundlagen
if
ist für den Kontrollfluss. Es ist nicht vektorisiert, dh es kann nur Bedingungen der Länge 1 auswerten. Es musselse
(optional) ein else-Wert zurückgegeben werden.ifelse
ist eine Funktion. Es ist vektorisiert und kann Werte beliebiger Länge zurückgeben. Das dritte Argument (der else-Wert) ist obligatorisch. *`if`
ist eine Funktion mit der gleichen Syntax wieifelse
. 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 ergibtFALSE
. Die Verwendung ist also nur dann sicher, wenn Sie sicher sind, dass die Bedingung immer vorliegtTRUE
, und wenn dies der Fall ist, warum beschäftigen Sie sich dann überhaupt mit einer if-Anweisung?Beispiele
Diese sind alle gleichwertig:
Beachten Sie, dass die Leerzeichen
else
nicht erforderlich sind, wenn Sie Zeichenfolgen direkt im Code verwenden: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 istTRUE
. Für eine Codezeileif
ist in der Regel Folgendes am besten:Bei mehreren Codezeilen
if
ist immer noch der Gewinner: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
if
und`if`
in der Byteanzahl äquivalent.Zusammenfassung
Verwenden
ifelse
Sie diese Option, wenn Sie eine Länge> 1 eingegeben haben.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ändigeif
...else
Aussage.Wenn Sie nur einen einzigen Wert möchten
TRUE
, verwenden Sieif
.Zur Ausführung von beliebigem Code,
`if`
undif
sind in der Regel die gleichen in Bezug auf die Anzahl der Bytes; Ich empfehle vorif
allem, weil es einfacher zu lesen ist.quelle
Sie können der aktuellen Umgebung eine Variable zuweisen und sie gleichzeitig als Argument für eine Funktion bereitstellen:
Wenn Sie a untergliedern
data.frame
und Ihre Bedingung von mehreren Spalten abhängt, können Sie vermeiden, dass derdata.frame
Name wiederholt wird, indem Siewith
(odersubset
) verwenden.Anstatt von
Das spart natürlich nur Zeichen, wenn die Länge Ihrer Verweise auf die
data.frame
die Länge von überschreitetwith(,)
if...else
blocks kann den Wert der finalen Anweisung zurückgeben, in der immer ein Teil des Blocks ausgeführt wird. Zum Beispiel anstelle vonDu kannst schreiben
quelle
f <- function(a,b) cat(a,b)
, dannf(a <- 'A', b <- 'B')
ist das nicht dasselbe wief(b <- 'B', a <- 'A')
.Implizite Typkonvertierung
Die Funktionen
as.character
,as.numeric
undas.logical
sind zu bytelastig. Kürzen wir sie.Umwandlung von numerisch nach logisch (4 Bytes)
Angenommen, es
x
handelt sich um einen numerischen Vektor. Durch die Verwendung des Operators "Logisch nicht" wird die!
Zahl implizit in einen logischen Vektor umgewandelt, wobei die Werte0
isFALSE
und ungleich null sindTRUE
.!
dann invertiert das.x=0:3;x=!x
kehrt zurückTRUE FALSE FALSE FALSE
.Umwandlung in Zeichen von numerisch oder logisch (7 Bytes)
Das macht Spaß. (Aus diesem Tweet .)
R sieht, dass Sie den Vektor
x
mit aktualisieren''
, der von Klasse istcharacter
. Es wird alsox
in eine Klasse umgewandelt,character
sodass es mit dem neuen Datenpunkt kompatibel ist. Als nächstes geht es setzen''
an der richtigen Stelle ... aber der Index0
existiert nicht (dieser Trick funktioniert auch mitInf
,NaN
,NA
,NULL
, und so weiter). Infolgedessenx
wird nur in der Klasse geändert.x=1:3;x[0]=''
kehrt zurück"1" "2" "3"
undx=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. ZBx[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:
Dies funktioniert, wenn
x
es 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:Der positive Operator neu gefasst implizit den Vektor als numerischer Vektor, so
TRUE FALSE
wird1 0
.quelle
x=+x
,TRUE
als zu halten1
.c(x,"")
ifx
is atomic verwenden, vorausgesetzt, Sie werden esx
in einer Funktion verwenden, die sich nur um das erste Element kümmert (es kann sich beschweren). Dies ist 1 Byte billiger alsx[0]="";
.Do-while-Schleifen in R
Gelegentlich wünsche ich mir, R hätte eine
do-while
Schleife, weil: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.Primitive
Funktionen in R.Die Dokumentation für sie lautet:
und unter Wert,
(Betonung hinzugefügt)
Also, was bedeutet das? Dies bedeutet, dass eine Do-While-Schleife so einfach ist wie
weil die in Ausdrücken
{}
jeder ausgewertet sind, und nur die letzte durch zurückgegeben{
, so dass wir bewertensome_code
vor dem Eintritt in die Schleife, und es läuft jedes Malcondition
istTRUE
(oder truthy). Dies0
ist einer der vielen 1-Byte-Ausdrücke, die den "echten" Körper derwhile
Schleife bilden.quelle
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.Verwenden Sie
Map
als Abkürzung fürmapply
. Mein Anspruch ist, dassmapply
es in Situationen, in denen Sie auf den Index zugreifen müssen, billiger ist als eine for-Schleife. Missbrauch der Listenstruktur in R.unlist
ist teuer.methods::el
Damit können Sie das erste Element kostengünstig aus der Liste entfernen. Versuchen Sie, Funktionen mit Listenunterstützung nativ zu verwenden.Verwenden Sie
do.call
diese Option, um Funktionsaufrufe mit beliebigen Eingaben zu verallgemeinern.Das Akkumulieren von Argumenten
Reduce
ist äußerst hilfreich für Code-Golf.Schreiben auf die Konsole Zeile für Zeile mit
cat(blah, "\n")
ist billiger mitwrite(blah, 1)
. Fest codierte Zeichenfolgen mit "\ n" sind in manchen Situationen möglicherweise billiger.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)
.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.
strsplit
ist alleinstehend für die Zerstörung des R-Golfs verantwortlich.Nun zu einigen neu entdeckten Tipps aus dem Jahr 2018
A[cbind(i,j)] = z
kann ein guter Weg sein, um Matrizen zu manipulieren. Diese Operation ist sehr byteeffizient, vorausgesetzt, Sie entwerfeni, j, z
Vektoren 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.Verwenden Sie eine neue Zeile anstelle von
\n
Zeilenumbrüchen.Wenn Sie die Anzahl der Zeilen verringern, können Sie Byte sparen. Inline-Zuweisung
lapply(A<-1:10,function(y) blah)
und Zuweisung von Funktionsargumentenfunction(X, U = X^2, V = X^3)
sind Möglichkeiten, dies zu tun.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 wiex[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ückquelle
"[<-"
verdient eine eigene "Tipps" -Antwort, da sie das geänderte Array / die geänderte Matrix / was auch immer zurückgibt.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
Sie können jedoch auch Werte inline speichern , um sie in derselben Zeile zu verwenden !
Zum Beispiel
Liest aus
stdin
, erstellt eine Variablex=1:n
und indiziert dannx
mit dem Wert vonx
. Dies kann manchmal Bytes sparen.Alias für den leeren Vektor Sie können ihn
{}
als leeren Vektor verwenden,c()
da beide zurückkehrenNULL
.Basis - Konvertierung Für ganzzahlige Ziffern
n
in der Basis 10, verwendenn%/%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)%%10
da sie kürzer als die Array-Indizierung ist. Dies kannfloor(log(n,b))+1
anstelle von an andere Basen angepasst werdennchar(n)
Verwenden von
seq
und:
: Anstatt1:length(l)
(oder1:sum(x|1)
) zu verwenden, können Sie verwendenseq(l)
, solangel
alist
oder einevector
Länge größer als 1 hat, wie dies standardmäßig der Fall istseq_along(l)
. Wennl
möglicherweise Länge sein könnte1
,seq(a=l)
wird der Trick.Zusätzlich
:
wird (mit einer Warnung) das erste Element seiner Argumente verwendet.Entfernen von Attributen Mit
c()
einemarray
(odermatrix
) wird dasselbe getan wie mitas.vector
; Im Allgemeinen werden Nicht-Namensattribute entfernt.Factorial Using
gamma(n+1)
ist kürzer als usingfactorial(n)
undfactorial
wird alsgamma(n+1)
ohnehin definiert .Coin Flipping Wenn Sie eine zufällige Aufgabe in 50% der Fälle ausführen müssen, ist using
rt(1,1)<0
kürzer alsrunif(1)<0.5
drei Bytes.Elemente extrahieren / ausschließen
head
undtail
sind 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:quelle
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ßerdem1:n*0
ist es kürzer alsIm(1:n)
zwei Bytes, was bedeutet, dass Ihr zweiter Stich auch sein kannx+0*-n:n
:-)!1:n
ist auch ein Array vonn
Nullen je nach Anwendungsfall; Wir danken jedoch der MATL / MATLAB-Tippfrage (wahrscheinlich Luis Mendo) für diese Frage.(log(i,b)%/%1):0)
stattfloor(log(n,b))+1
?Einige grundlegende Konzepte sollten aber etwas nützlich sein:
In Kontrollflussanweisungen können Sie missbrauchen, dass jede Zahl ungleich Null als ausgewertet wird
TRUE
, z. B .:if(x)
entsprichtif(x!=0)
. Umgekehrtif(!x)
ist gleichbedeutend mitif(x==0)
.Bei der Generierung von Sequenzen mit
:
(zB1:5
) kann man die Tatsache missbrauchen, dass der Exponentiationsoperator^
der einzige Operator ist, der Vorrang vor dem:
Operator hat (im Gegensatz zu+-*/
).Dies erspart Ihnen zwei Bytes in den Klammern, die Sie normalerweise verwenden müssten, wenn Sie z. B. über die Elemente einer
n x n
Matrix (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 .Ein verwandter Trick kann natürlich auch für vektorisierte Operationen verwendet werden
+-*/
, obwohl er am häufigsten für Folgendes gilt+-
:Dies funktioniert, weil
+1
vektorisiert und1
zu jedem Element des0:n
Vektors addiert wird1 2 ... n+1
. Ebenso0:(n+1) == -1:n+1
spart man auch ein Byte.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
{...}
:Beachten Sie, dass dies möglicherweise nicht immer den Regeln bestimmter Herausforderungen entspricht.
quelle
^
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?Syntax
fü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.Ä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: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:
Das bedeutet nun, dass diese beiden Codezeilen dasselbe tun:
und Vorrang wird respektiert, was zu Dingen wie führt
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:Siehe zum Beispiel diese Antwort .
Siehe auch diese Antwort zur Verwendung
[
als Zwei-Byte-Operator mit drei Argumenten.quelle
<
hat eine niedrigere Priorität als+
, aber*
eine höhere Priorität als,+
so dass Sie sie möglicherweise miteinander verketten können!?
anpaste
oder eine andere Funktion , die zwei Argumente nehmen, die Rangfolge bedeutet , dass Sie immer noch Inline - Zuweisungen über nutzen könnena<-b?d<-e
.[
einen Alias mit drei Elementen hinzufügen (das sind zwei Bytes). Ich finde es oft hilfreich für Dinge wieouter
(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.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 vonpaste0(letters,collapse="")
Ein 2-Byte-Golf, bei dem Sie eine Liste mit zwei Vektoren haben
c(1,2,3)
undc(4,5,6)
diese elementweise zu einer Zeichenfolge verketten möchten"142536"
. Betreibermissbrauch gibt Ihnenp=paste0;"^"=Reduce;p^p^r
die Möglichkeit, beim normalenpaste0
Anruf 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 .
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 vorgezogenfunction(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 Stringscan
alstext
Argument an und trennt ihn durch Leerzeichen.Das zweite Argument in
scan
kann eine beliebige Zeichenfolge sein. Wenn Sie also eine erstellt haben, können Sie diese recyceln , um ein Byte zu speichern.Wenn Sie eine Eingabezeichenfolge in einen Zeichenvektor umwandeln müssen :
x=el(strsplit(s,""))
ist die kürzeste allgemeine Lösung. Dassplit
Argument funktioniert auf etwas mit der Länge Null einschließlichc()
,{}
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
, dautf8ToInt(x)
kürzer als derstrsplit
Aufruf ist. Das ZusammenfügenintToutf8(utf8ToInt(x))
ist kürzer alsReduce(paste0,el(strsplit(x,"")))
.Wenn Sie beliebige Zahlenfolgen wie
"31415926535"
bei der Eingabe teilen müssen , können Sieutf8ToInt(s)-48
3 Bytes einsparenel(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
intToUtf8
oderchartr
Anwendung auf eine Sequenz übera:b
oder auf die eingebauten Buchstabensätzeletters
oder anLETTERS
. Die eingebaute Mustersprachechartr
ist 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
scan
mitstdin
alsfile
arg:Wenn
scan
ausstdin
nicht möglich ist, für 6 oder mehr nicht Leerzeichen oder Wörter , verwenden Siescan
mit demtext
Argumentscan(,"",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
strsplit
viax=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ögenstrrep
undgrep
werden 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
strsplit
von Wörtern überx=el(strsplit("q w e r t y"," "))
. Es verliert immerscan(,"",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 Ausnahmestrsplit
auf""
das funktioniert nur auf Zeichen.c. Wenn Sie Text als Zeichenmatrix eingeben müssen , sind einige Rezepte kurz
quelle
scan
hat eintext
Argument, das wettbewerbsfähiger ist, alsel(strsplit(x," "))
wenn Sie nur Zeichenfolgen benötigen! Probieren Sie es online! Im Gegensatz zu Ihrem letzten Vorschlag vonread.csv
.scan
bis zu 5 Zeichen besser,el(strsplit(x,""))
ist wettbewerbsfähiger alsscan
für 6 oder mehr. Probieren Sie es online! Ich habe noch keine gute Verwendung für gefundenread.csv
, aber vielleicht wäre es nützlich, wenn Sie aus irgendeinem Grund eine Datentabelle benötigen würden?data.frame
aber vielleicht müssen wir eine Herausforderung finden / erstellen, wo es hilfreich wäre! Vielleicht eindplyr
Stilgroup_by()
und einesummarize()
Art der Manipulation? IDK.scan(,"")
scheint das noch besser? Probieren Sie es online!scan
praktisch.Einige Möglichkeiten, um das erste Nicht-Null-Element eines Arrays zu finden.
Wenn es einen Namen hat
x
:Gibt zurück,
NA
wenn keine Elemente ungleich Null vorhanden sind (einschließlich wannx
leer, aber nichtNULL
welche Fehler).Anonym:
Gibt zurück,
NULL
wenn keine Elemente ungleich Null oder leer oderNULL
.quelle
NA
wenn alle Elemente vonx
Null sind, glaube ich.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. TIOFind
ist auch ein bisschen sicherer, wenn es funktioniertNULL
, solange nichts anderes mit dem Ergebnis geschehen muss. In diesem Fall bin ich mir nicht sicher, ob ich zurückkommeNA
oderNULL
sicherer bin .sign(Find(c,w))
was fehler verursacht hat - musste machenFind(c,sign(w))
um es nicht fehler zu machen . Ich denke, beide Wege haben ihren Nutzen.Alternativen zu
rep()
rep()
Mit dem Doppelpunktoperator:
und dem Vektorrecycling von R kann dies manchmal vermieden werden .Zum Wiederholen
n
Nullen, won>0
,0*1:n
ist 3 Bytes kürzer alsrep(0,n)
und!1:n
ein Feld vonFALSE
ist 4 Bytes kürzer, wenn der Anwendungsfall dies zulässt.Um die
x
n
Zeiten zu wiederholen ,x+!1:n
ist 2 Bytes kürzer alsrep(x,n)
.n
Verwenden!!1:n
Sie für diejenigen, wenn Sie ein Array von verwenden könnenTRUE
.Um es zu wiederholen
x
2n+1
Zeiten, won>=0
,x+0*-n:n
ist 4 Byte kürzer alsrep(x,2*n+1)
.Die Aussage
!-n:n
wirdTRUE
von beiden Seiten flankiertn
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.
rep
Anweisungen mit demeach
Argument 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%/%3
ist 5 Bytes kürzer alsrep(-1:1,e=3)
.Um den Vektor zu erzeugen
c(0,1,2,0,1,2,0,1,2)
,0:8%%3
speichert 4 Byte aufrep(0:2,3)
.Manchmal können nichtlineare Transformationen die Sequenzarithmetik verkürzen. Zur Karte
i in 1:15
zuc(1,1,3,1,1,3,1,1,3,1,1,3,1,1,3)
innerhalb einer zusammengesetzten Anweisung, die offensichtliche Golfy Antwort ist1+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.quelle
Wenn Sie eine Funktion verwenden müssen, verwenden Sie
pryr::f()
anstelle vonfunction()
.Beispiel:
ist äquivalent zu
oder noch besser
Da Wenn es nur ein Argument gibt, werden die Formale aus dem Code erraten .
quelle
function(x,y){x+y}
kann geschrieben werden wiefunction(x,y)x+y
für denselben bytecount,pryr::f(x,y,x+y)
aber mit besserer Lesbarkeit.Überleben Herausforderungen mit Streichern
Wie in einer anderen Antwort erwähnt,
unlist(strsplit(x,split="")
undpaste(...,collapse="")
kann deprimierend sein. Aber gehen Sie nicht einfach davon weg, es gibt Workarounds!utf8ToInt
Konvertiert einen String in einen Vektor,intToUtf8
führt die umgekehrte Operation durch. Sie erhalten einen Vektor vonint
, keinen Vektor von,char
aber manchmal ist es das, wonach Sie suchen. Zum Beispiel, um eine Liste zu generieren-
, die besserintToUtf8(rep(45,34))
alspaste(rep("-",34),collapse="")
gsub
ist nützlicher als andere Funktionen dergrep
Familie, 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 .<
die Zeichenfolgen wie erwartet lexikografisch verglichen.quelle
intToUtf8
Es gibt auch ein zweites Argument,multiple = FALSE
das vonint
s in einzelne Zeichen (Zeichenfolgen mit der Länge eins) konvertiert, und nicht in eine einzelne Zeichenfolge, wenn es auf gesetzt istTRUE
.allow_surrogate_pairs = FALSE
, aber ich weiß nicht, was es bewirkt. Die Docs sagen etwas über das Lesen von zwei Bytes als ein,UTF-16
aber ich weiß kaum, was dasUTF-8
ist. Ich werde es einfach ignorieren, bis jemand anderes einen Weg findet, damit Golf zu spielen.Tipps für Probleme mit eingeschränkten Quellen:
Zeichen in R-Literalkonstanten können durch Hex-Codes, Oktal-Codes und Unicodes ersetzt werden.
zB kann der String
"abcd"
geschrieben werden: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:
Weitere Einzelheiten finden Sie am Ende dieses Abschnitts .
Da Funktionen mit String-Literalen geschrieben werden können,
cat()
kann zB alternativ geschrieben werden:Wir können auch Oktalcodes, Hex-Codes und Unicode für Funktionsnamen verwenden:
mit der einzigen Ausnahme, dass Unicode-Sequenzen in Backticks `` nicht unterstützt werden
Runde Klammern können den Missbrauch von Operatoren verhindern, zB:
Eine Anwendung aller drei Tricks finden Sie in dieser Antwort
quelle
0xB
und0xb
zurückgegeben werden11
(Backticks oder Anführungszeichen sind nicht erforderlich).