Szukam wskazówek dotyczących gry w golfa w języku statystycznym R. R jest być może niekonwencjonalnym wyborem dla golfa. Jednak robi pewne rzeczy bardzo zwięźle (sekwencje, losowość, wektory i listy), wiele wbudowanych funkcji ma bardzo krótkie nazwy i ma opcjonalny terminator linii (;). Jakie wskazówki i porady możesz pomóc rozwiązać problemy z kodem do golfa w R?
58
Odpowiedzi:
Kilka porad:
<-
ponad=
. W przypadku golfa sytuacja jest odwrotna, ponieważ=
jest krótszy ...Jeśli wywołujesz funkcję więcej niż raz, często korzystne jest zdefiniowanie krótkiego aliasu:
Częściowe dopasowanie może być twoim przyjacielem, szczególnie gdy funkcje zwracają listy, których potrzebujesz tylko jednego elementu. Porównaj
rle(x)$lengths
zrle(x)$l
Wiele wyzwań wymaga przeczytania danych wejściowych.
scan
często jest do tego odpowiedni (użytkownik kończy wprowadzanie danych przez wprowadzenie pustej linii).Przymus może być przydatny.
t=1
jest znacznie krótszy niżt=TRUE
. Alternatywnie,switch
możesz również zaoszczędzić cenne postacie, ale będziesz chciał użyć 1,2 zamiast 0,1.Jeśli funkcja oblicza coś skomplikowanego i potrzebujesz różnych innych rodzajów obliczeń opartych na tej samej wartości podstawowej, często korzystne jest: a) rozbicie jej na mniejsze funkcje, b) zwrócenie wszystkich potrzebnych wyników w postaci listy lub c) niech zwraca różne typy wartości w zależności od argumentu funkcji.
Jak w każdym języku, dobrze go znam - R ma tysiące funkcji, prawdopodobnie jest kilka, które mogą rozwiązać problem za pomocą bardzo niewielu znaków - sztuką jest wiedzieć, które z nich!
Niektóre niejasne, ale przydatne funkcje:
Niektóre wbudowane zestawy danych i symbole:
źródło
Zamiast importować pakiet za pomocą
library
, pobierz zmienną z pakietu za pomocą::
. Porównaj następujące:Oczywiście jest to poprawne tylko wtedy, gdy z pakietu używana jest jedna funkcja.
Jest to trywialna, ale ogólna zasada, kiedy należy użyć sztuczki @ Tommy polegającej na aliasingu funkcji: jeśli nazwa funkcji ma długość
m
i jest używanan
razy, to alias tylko wtedy, gdym*n > m+n+3
(ponieważ podczas definiowania aliasu wydajesz,m+3
a następnie nadal wydajesz 1 za każdym razem, gdy używany jest alias). Przykład:Przymus jako efekt uboczny funkcji:
zamiast używać
as.integer
ciąg znaków można przekonwertować na liczbę całkowitą, używając:
:liczba całkowita, numeryczna itp. może być podobnie wymuszona na znak, używając
paste
zamiastas.character
:źródło
el("19":1)
jest jeszcze krótsza o jeden bajt.Kilka bardzo specyficznych wskazówek golfowych:
sum(x|1)
jest on krótszy niżlength(x)
tak długi, jakx
numeryczny, całkowity, złożony lub logiczny.rev()
a następnie wywołaniex[1]
zamiastx[length(x)]
(lub przy użyciu powyższej wskazówkix[sum(x|1)]
) (lubtail(x,1)
--- dzięki Giuseppe!). Nieznaczna odmiana tej sprawie (gdzie przedostatni element został potrzeby) widać tu . Nawet jeśli nie można zainicjować wektora od tyłu,rev(x)[1]
jest on nadal krótszy niżx[sum(x|1)]
(i działa również w przypadku wektorów znaków). Czasami nawet nie potrzebujeszrev
, na przykład używanian:1
zamiast1:n
.(Jak widać tutaj ). Jeśli chcesz przymusić ramkę danych do macierzy, nie używaj
as.matrix(x)
. Weź transpozycję do transpozycjit(t(x))
.if
jest funkcją formalną. Na przykład"if"(x<y,2,3)
jest krótszy niżif(x<y)2 else 3
(choć oczywiście3-(x<y)
krótszy niż którykolwiek z nich). Zapisuje to tylko postacie, jeśli nie potrzebujesz dodatkowej pary nawiasów klamrowych, aby sformułować to w ten sposób, co często robisz.Do testowania nierówności obiektów numerycznych
if(x-y)
jest krótszy niżif(x!=y)
. Każda niezerowa liczba jest traktowana jakoTRUE
. Jeśli testujesz równość, powiedzmy,if(x==y)a else b
spróbujif(x-y)b else a
zamiast tego. Zobacz także poprzedni punkt.Ta funkcja
el
jest przydatna, gdy musisz wyodrębnić element z listy. Najczęstszym przykładem jest prawdopodobniestrsplit
:el(strsplit(x,""))
jest o jeden mniej bajtów niżstrsplit(x,"")[[1]]
.(Jak tutaj użyto ) Rozszerzenie wektora może oszczędzić ci znaków: jeśli wektor
v
ma długośćn
, możesz przypisać gov[n+1]
bezbłędnie. Na przykład, jeśli chcesz wydrukować pierwsze dziesięć silni, które możesz zrobić:v=1;for(i in 2:10)v[i]=v[i-1]*i
zamiastv=1:10:for(...)
(choć jak zawsze istnieje inny, lepszy sposóbcumprod(1:10)
:)Czasami w przypadku wyzwań opartych na tekście (szczególnie w 2D) łatwiej jest
plot
tekstowi niżcat
go. argumentpch=
doplot
kontroli, które znaki są wykreślone. Można to skrócić dopc=
(co da również ostrzeżenie), aby zapisać bajt. Przykład tutaj .Aby zabrać głos pewnej liczbie, nie używaj
floor(x)
. Użyjx%/%1
zamiast tego.Aby sprawdzić, czy wszystkie elementy wektora liczbowego lub liczb całkowitych są równe, często można użyć
sd
zamiast czegoś pełnego, takiego jakall.equal
. Jeśli wszystkie elementy są takie same, ich odchylenie standardowe wynosi zero (FALSE
), w przeciwnym razie odchylenie standardowe jest dodatnie (TRUE
). Przykład tutaj .Niektóre funkcje, których należy oczekiwać od liczb całkowitych, w rzeczywistości tego nie robią. Na przykład
seq(3.5)
zwróci1 2 3
(to samo dotyczy:
operatora). Pozwala to uniknąć połączeń z,floor
a czasem oznacza, że możesz użyć/
zamiast%/%
.źródło
tail(v,1)
ma również taką samą długość jakrev(v)[1]
końcówka golfowa „ostatni element tablicy”.read.csv(t="a,b,c",,F)
jest krótszy niżel(strsplit("a,b,c",","))
.T
iF
. Domyślnie oceniają naTRUE
iFALSE
, które można automatycznie przekonwertować na wartości liczbowe1
i0
, i można je ponownie zdefiniować do woli. Oznacza to, że nie musisz inicjować licznika (np.i=0
...i=i+1
), możesz po prostu użyćT
lubF
w razie potrzeby (i przejść od razu doF=F+1
później).return()
wywołania.Świetne jest definiowanie krótkich aliasów dla często używanych funkcji, takich jak
p=paste
. Jeśli często używasz funkcji i przy dokładnie dwóch argumentach, możliwe, że alias naprawczy zaoszczędzi ci trochę bajtów. Naprzemienne aliasy muszą być otoczone%
. Na przykład:A następnie
x%p%y
, który jest o 1 bajt krótszy niżp(x,y)
. Definicja aliasu naprawczego jest jednak o 4 bajty dłuższa niż niefiksowaniep=paste
, więc musisz być pewien, że warto.źródło
`+`=paste; x+y
Korzystanie
if
,ifelse
oraz`if`
Istnieje kilka sposobów wykonywania instrukcji if w R. Rozwiązania optymalne dla golfa mogą się bardzo różnić.
Podstawy
if
służy do sterowania przepływem. Nie jest wektoryzowany, tzn. Może oceniać tylko warunki długości 1. Wymagaelse
(opcjonalnie) zwrócenia innej wartości.ifelse
jest funkcją. Jest wektoryzowany i może zwracać wartości o dowolnej długości. Trzeci argument (wartość else) jest obowiązkowy. *`if`
jest funkcją o takiej samej składni jakifelse
. Nie jest wektoryzowany, żaden z argumentów zwrotnych nie jest obowiązkowy.* Nie jest to technicznie obowiązkowe;
ifelse(TRUE,x)
działa dobrze, ale generuje błąd, jeśli trzeci argument jest pusty, a warunek zostanie ocenionyFALSE
. Można go bezpiecznie używać tylko wtedy, gdy masz pewność, że warunek jest zawszeTRUE
, a jeśli tak, to dlaczego w ogóle zawracasz sobie głowę instrukcją if?Przykłady
Wszystkie są równoważne:
Zauważ, że spacje wokół
else
nie są wymagane, jeśli używasz ciągów bezpośrednio w kodzie:Jak dotąd
`if`
wydaje się być zwycięzcą, o ile nie mamy wektoryzacji danych wejściowych. Ale co z przypadkami, w których nie dbamy o inny stan? Powiedzmy, że chcemy wykonać część kodu tylko wtedy, gdy jest to warunekTRUE
.if
Zwykle najlepszy jest tylko jeden wiersz kodu :W przypadku wielu wierszy kodu
if
nadal wygrywa:Istnieje również możliwość, gdzie należy dbać o stan innego, i gdzie chcemy wykonać dowolny kod zamiast zwracać wartość. W takich przypadkach
if
i`if`
są równoważne w liczbie bajtów.Podsumowanie
Użyj,
ifelse
gdy wprowadzisz długość> 1.Jeśli zwracasz prostą wartość zamiast wykonywania wielu wierszy kodu, użycie
`if`
funkcji jest prawdopodobnie krótsze niż pełnaif
...else
instrukcja.Jeśli chcesz tylko jednej wartości
TRUE
, użyjif
.Do wykonania dowolnego kodu
`if`
iif
zwykle są takie same pod względem liczby bajtów; Polecamif
głównie dlatego, że jest łatwiejszy do odczytania.źródło
Możesz przypisać zmienną do bieżącego środowiska, jednocześnie podając ją jako argument do funkcji:
Jeśli wpisujesz a,
data.frame
a twój stan zależy od kilku jego kolumn, możesz uniknąć powtarzaniadata.frame
nazwy za pomocąwith
(lubsubset
).zamiast
Oczywiście zapisuje to znaki tylko wtedy, gdy długość twoich referencji
data.frame
przekracza długośćwith(,)
if...else
bloki mogą zwracać wartość instrukcji końcowej, w której wykonywana jest kiedykolwiek część bloku. Na przykład zamiastMożesz pisać
źródło
f <- function(a,b) cat(a,b)
,f(a <- 'A', b <- 'B')
to nie jest to samo cof(b <- 'B', a <- 'A')
.Niejawna konwersja typu
Funkcje
as.character
,as.numeric
ias.logical
są zbyt ciężkie bajt. Przytnijmy je.Konwersja na logiczny z numerycznego (4 bajty)
Załóżmy, że
x
jest wektorem numerycznym. Użycie operatora logicznego not!
niejawnie przekształca wartość liczbową w wektor logiczny, gdzie0
jestFALSE
i są wartości niezeroweTRUE
.!
następnie odwraca to.x=0:3;x=!x
zwracaTRUE FALSE FALSE FALSE
.Konwersja znaków na postać numeryczną lub logiczną (7 bajtów)
To jest zabawne. (Z tego tweeta .)
R widzi, że jesteś aktualizowanie wektor
x
z''
, czyli klasycharacter
. Rzuca więcx
na klasę,character
dzięki czemu jest kompatybilny z nowym punktem danych. Następnie przechodzi się umieścić''
w odpowiednim miejscu ... ale indeks0
nie istnieje (ten trik działa również zInf
,NaN
,NA
,NULL
, i tak dalej). W rezultaciex
jest modyfikowany tylko w klasie.x=1:3;x[0]=''
zwraca"1" "2" "3"
ix=c(TRUE,FALSE);x[0]=''
zwraca"TRUE" "FALSE"
.Jeśli masz już znak obiektu w swoim obszarze roboczym, możesz go użyć zamiast
''
zapisać bajt. Np.x[0]=y
!Konwersja znaków na postać liczbową lub logiczną pod pewnymi warunkami (6 bajtów)
J.Doe wskazał w komentarzach sześciobajtowe rozwiązanie:
Działa
x
to, jeśli jest atomowy i jeśli zamierzasz przekazać go do funkcji, która wymaga wektora atomowego. (Funkcja może generować ostrzeżenie o ignorowaniu elementów argumentu.)Konwersja na numeryczną z logicznej (4 bajty)
Możesz użyć funky sztuczki indeksowania z góry (np.
x[0]=3
), Ale w rzeczywistości jest szybszy sposób:Operator dodatni domyślnie przekształca wektor jako wektor numeryczny, tak się
TRUE FALSE
dzieje1 0
.źródło
x=+x
, aby utrzymaćTRUE
jak1
.c(x,"")
ifx
jest atomowa, pod warunkiem, że będziesz używałx
funkcji, która dba tylko o pierwszy element (może narzekać). Jest to 1 bajt tańszy niżx[0]="";
.Pętle do-while w R.
Czasami żałuję, że R nie ma
do-while
pętli, ponieważ:jest zdecydowanie za długi i bardzo nie golfowy. Możemy jednak przywrócić to zachowanie i zgolić niektóre bajty dzięki sile
{
funkcji.{
i(
każda z.Primitive
funkcji jest w R.Dokumentacja dla nich brzmi:
i poniżej wartości,
(podkreślenie dodane)
Co to znaczy? Oznacza to, że pętla „do-while” jest tak prosta jak
ponieważ wyrażenia wewnątrz
{}
każdorazowo oceniane i tylko ostatnia jest zwracany przez{
, co pozwala nam ocenićsome_code
przed wejściem do pętli, i to działa za każdym razemcondition
jestTRUE
(lub truthy). Jest0
to jedno z wielu wyrażeń 1-bajtowych, które tworzą „prawdziwe” ciałowhile
pętli.źródło
Nadużycie w
outer
celu zastosowania dowolnej funkcji do wszystkich kombinacji dwóch list. Wyobraź sobie macierz z indeksami i, j indeksowanymi przez pierwsze argumenty, a następnie możesz zdefiniować dowolną funkcję (i, j) dla każdej pary.Użyj
Map
jako skrótu domapply
. Uważam, żemapply
jest tańszy niż pętla for w sytuacjach, w których musisz uzyskać dostęp do indeksu. Nadużywanie struktury listy w R.unlist
jest drogie.methods::el
pozwala tanio usunąć pierwszy element z listy. Spróbuj użyć funkcji z obsługą listy natywnie.Służy
do.call
do uogólnienia wywołań funkcji z dowolnymi danymi wejściowymi.Gromadzenie argumentów
Reduce
jest niezwykle pomocne dla golfa kodowego.Pisanie do konsoli linia po linii
cat(blah, "\n")
jest tańszewrite(blah, 1)
. Ciągi zakodowane na stałe z „\ n” mogą być tańsze w niektórych sytuacjach.Jeśli funkcja ma domyślne argumenty, możesz użyć funkcji (,, n-arg), aby bezpośrednio określić n-ty argument. Przykład:
seq(1, 10, , 101)
W niektórych funkcjach obsługiwane jest częściowe dopasowanie argumentów. Przykład:seq(1, 10, l = 101)
.Jeśli zobaczysz wyzwanie polegające na manipulacji ciągiem, po prostu naciśnij przycisk Wstecz i przeczytaj następne pytanie.
strsplit
jest samotnym, odpowiedzialnym za zrujnowanie R golfa.Teraz kilka nowych odkryć z 2018 roku
A[cbind(i,j)] = z
może być dobrym sposobem na manipulowanie macierzami. Ta operacja jest bardzo wydajna bajtowo przy założeniu, że projektujeszi, j, z
jako wektory o prawidłowych długościach. Możesz zaoszczędzić jeszcze więcej, wywołując rzeczywistą funkcję indeksu / przypisania"[<-"(cbind(i,j), z)
. Ten sposób wywoływania zwraca zmodyfikowaną macierz.Użyj nowej linii zamiast
\n
podziałów linii.Zmniejszenie liczby wierszy może zaoszczędzić bajty. Przypisywanie w linii
lapply(A<-1:10,function(y) blah)
i przypisywanie argumentów funkcjifunction(X, U = X^2, V = X^3)
są na to sposobem.Podobnie
"[<-"
jest funkcja w R (i jest związana z moim starożytnym pytaniem na SO )! Jest to podstawowa funkcja odpowiedzialna za operacje takie jakx[1:5] = rnorm(5)
. Dobra właściwość wywołania funkcji według nazwy umożliwia zwrócenie zmodyfikowanego wektora. W kolejności słowa"[<-"(x, 1:5, normr(5))
robi prawie to samo, co powyższy kod, z tym wyjątkiem, że zwraca zmodyfikowane x. Powiązane „długość <-”, „nazwy <-”, „cokolwiek <-” zwracają zmodyfikowane dane wyjścioweźródło
"[<-"
jest warte własnej odpowiedzi „Wskazówki”, ponieważ zwróci zmodyfikowaną tablicę / macierz / cokolwiek.Zapisz wartości w linii : inni wspominali, że możesz przekazywać wartości w kolejności i przypisywać je do użycia w innym miejscu, np
Możesz jednak również zapisać wartości bezpośrednio w celu użycia w tym samym wierszu !
Na przykład
czyta z
stdin
, tworzy zmiennąx=1:n
, a następnie indeksuje dox
użycia tej wartościx
. Może to czasem zaoszczędzić bajty.Alias dla pustego wektora Można użyć
{}
jako pustego wektora,c()
gdy oba się wrócąNULL
.Konwersja bazy Dla cyfr całkowitych z
n
bazy 10, użyjn%/%10^(0:nchar(n))%%10
. To pozostawi końcowe zero, więc jeśli jest to dla ciebie ważne, użyj,n%/%10^(1:nchar(n)-1)%%10
ponieważ jest krótszy niż indeksowanie tablicy. Można to dostosować do innych baz, używającfloor(log(n,b))+1
zamiastnchar(n)
Używanie
seq
i:
: Zamiast używania1:length(l)
(lub1:sum(x|1)
), możesz użyćseq(l)
tak długo, jakl
jest alist
lubvector
o długości większej niż 1, jak domyślnieseq_along(l)
. Jeślil
potencjalnie może być długość1
,seq(a=l)
załatwi sprawę.Dodatkowo
:
użyje (z ostrzeżeniem) pierwszego elementu swoich argumentów.Usuwanie atrybutów Korzystanie
c()
zarray
(lubmatrix
) spowoduje to samo, coas.vector
; ogólnie usuwa atrybuty inne niż nazwy.Używanie czynnikowe
gamma(n+1)
jest krótsze niż używaniefactorial(n)
i i takfactorial
jest zdefiniowanegamma(n+1)
.Rzut monetą Gdy potrzebujesz wykonać losowe zadanie w 50% przypadków, użycie
rt(1,1)<0
jest krótsze niżrunif(1)<0.5
o trzy bajty.Wyodrębnianie / wykluczanie elementów
head
itail
często są przydatne do wyodrębnienia pierwszych / ostatnich kilku elementów tablicy;head(x,-1)
wyodrębnia wszystkie oprócz ostatniego elementu i jest krótszy niż przy użyciu indeksowania ujemnego, jeśli nie znasz jeszcze długości:źródło
rep
”. Inne pytania ze wskazówkami mają jedną wskazówkę na odpowiedź, którą z całego serca popieram również w przypadku tego pytania! Jest także1:n*0
krótszy niżIm(1:n)
dwa bajty, co oznacza, że twoja druga sztuczka może byćx+0*-n:n
również :-)!1:n
to także tablican
zer w zależności od przypadku użycia; zasługuje na to pytanie MATL / MATLAB (prawdopodobnie Luis Mendo).(log(i,b)%/%1):0)
zamiastfloor(log(n,b))+1
?Niektóre podstawowe pojęcia, ale powinny być nieco przydatne:
W instrukcjach przepływu sterowania można nadużyć, że dowolna liczba nie równa zero będzie oceniana jako
TRUE
, np.:if(x)
Jest równaif(x!=0)
. I odwrotnie,if(!x)
jest równoważne zif(x==0)
.Podczas generowania sekwencji przy użyciu
:
(np.1:5
) Można nadużyć faktu, że operator potęgowania^
jest jedynym operatorem, który ma pierwszeństwo przed operatorem:
(w przeciwieństwie do+-*/
).co pozwala zaoszczędzić dwa bajty w nawiasach, których normalnie musiałbyś użyć, gdybyś chciał np. zapętlić elementy
n x n
macierzy (1:n^2
) lub innej liczby całkowitej, którą można wyrazić w krótszy sposób za pomocą notacji wykładniczej (1:10^6
).+-*/
Pokrewną sztuczkę można oczywiście również zastosować w operacjach wektoryzowanych , chociaż najczęściej stosuje się ją do+-
:Działa
+1
to, ponieważ jest wektoryzowane i dodaje1
do każdego elementu0:n
wynikającego z wektora1 2 ... n+1
. Podobnie0:(n+1) == -1:n+1
oszczędza również jeden bajt.Pisząc krótkie funkcje (które można wyrazić w jednym wierszu), można nadużyć przypisania zmiennej, aby zapisać dwa bajty w otaczających nawiasach klamrowych
{...}
:Pamiętaj, że nie zawsze może to być zgodne z zasadami określonych wyzwań.
źródło
^
jest wektoryzowana, po prostu ma pierwszeństwo przed:
(tzn. Jest wykonywana wcześniej,:
chyba że nawiasy wyraźnie wskazują na coś przeciwnego, zobacz?Syntax
dokładną kolejność pierwszeństwa operatorów binarnych i jednoargumentowych). To samo dotyczy plików binarnych,+-/*
które mają niższy priorytet niż:
stąd twoja sztuczka nr 3.Zmień znaczenie operatorów
Operatory R są tylko funkcjami, które są specjalnie traktowane przez analizator składni. Na przykład
<
jest w rzeczywistości funkcją dwóch zmiennych. Te dwa wiersze kodu robią to samo:Możesz ponownie przypisać inną funkcję do operatora, a analizator składni nadal to zrobi, w tym przestrzegając pierwszeństwa operatora, ale końcowe wywołanie funkcji będzie nowe, a nie oryginalne. Na przykład:
teraz oznacza, że te dwa wiersze kodu robią to samo:
i pierwszeństwo jest przestrzegane, czego skutkiem są rzeczy takie jak
Zobacz na przykład tę odpowiedź , a także stronę pierwszeństwa operatora . Jako efekt uboczny, twój kod stanie się tak tajemniczy, jak kod napisany w języku golfowym.
Niektórzy operatorzy lubią
+
i-
akceptują jeden lub dwa parametry, więc możesz nawet wykonywać następujące czynności:Zobacz na przykład tę odpowiedź .
Zobacz także tę odpowiedź dotyczącą używania
[
jako dwubajtowego, trzyargumentowego operatora.źródło
<
ma niższy priorytet niż+
, ale*
ma wyższy priorytet niż,+
więc możesz potencjalnie połączyć je razem!?
zpaste
jakąś inną funkcją, która może przyjąć dwa argumenty, kolejność pierwszeństwa oznacza, że nadal możesz używać przypisań wbudowanych za pośrednictwema<-b?d<-e
.[
jako trzyelementowy alias (to dwa bajty); Często uważam, że jest to pomocne w przypadku takich rzeczyouter
(i konsekwentnie o tym zapominam!), Chociaż oczywiście musisz upewnić się, że tak naprawdę nie musisz używać[
. Przydałby się również link do strony z pierwszeństwem operatora, aby pomóc w wyborze aliasu.Scenariusze, w których można uniknąć
paste(...,collapse="")
istrsplit
Są to trudności w zwykłych wyzwaniach strunowych. Istnieje kilka obejść.
Reduce(paste0,letters)
dla -5 bajtów odpaste0(letters,collapse="")
2-bajtowy golf gdzie masz listę zawierającą dwa wektory
c(1,2,3)
ac(4,5,6)
i chcesz złączyć je elementem mądry na łańcuch"142536"
. Wykorzystanie przez operatora daje cip=paste0;"^"=Reduce;p^p^r
oszczędność dwóch bajtów podczas zwykłegopaste0
połączenia.Zamiast
paste0("(.{",n,"})")
konstruować (np.) Wyrażenie regularne dla 20 bajtów, rozważ wyrażenie regularne w wyrażeniu regularnym:sub(0,"(.{0})",n)
dla 17 bajtów.Czasami (w rzeczywistości dość często) trzeba iterować wektor znaków lub ciągów znaków lub dzielić słowo na litery. Istnieją dwa typowe przypadki użycia: jeden, w którym trzeba wziąć wektor znaków jako dane wejściowe do funkcji lub programu, i drugi, w którym znasz wektor wcześniej i musisz go gdzieś zapisać w kodzie.
za. Gdzie trzeba wziąć ciąg wejściowy i podzielić go na słowa lub znaki .
Jeśli potrzebujesz słów (w tym znaków w specjalnym przypadku):
Jeśli nowa linia
0x10
(ASCII 16) oddzielająca słowa jest w porządku,x=scan(,"")
zaleca się zawijanie kodufunction(s,x=el(strsplit(s," ")))
.Jeśli słowa mogą być oddzielone od jakiejkolwiek innej białych znaków , w tym wielokrotnych spacji, tabulacji, znaki nowej linii itp, można użyć @ NGM za podwójną sztuczki skanowania :
x=scan(,"",t=scan(,""))
. Daje to zeskanowany ciąg znakówscan
jakotext
argument i oddziela go spacjami.Drugim argumentem
scan
może być dowolny ciąg, więc jeśli go utworzyłeś, możesz go przetworzyć, aby zapisać bajt.Jeśli chcesz zmienić ciąg wejściowy na wektor znaków :
x=el(strsplit(s,""))
jest najkrótszym ogólnym rozwiązaniem.split
Argumentem działa na niczym długości zerowej tymc()
,{}
etc więc jeśli zdarzy się, że stworzył zmiennej długości zero, można użyć go zapisać bajt.Jeśli możesz pracować z kodami znaków ASCII, zastanów się
utf8ToInt
, ponieważutf8ToInt(x)
jest on krótszy niżstrsplit
połączenie. Wklejenie ich z powrotemintToutf8(utf8ToInt(x))
jest krótsze niżReduce(paste0,el(strsplit(x,"")))
.Jeśli chcesz podzielić dowolne ciągi liczb, takie
"31415926535"
jak dane wejściowe, możesz użyć,utf8ToInt(s)-48
aby zapisać 3 bajtyel(strsplit(s,""))
, pod warunkiem, że możesz użyć cyfr całkowitych zamiast znaków, jak to często bywa. Jest to również krótszy niż zwykły przepis na dzielenie liczb na cyfry dziesiętne.b. Gdzie potrzebujesz wcześniej ustalonego wektora słów lub znaków.
Jeśli potrzebujesz wektora pojedynczych znaków, które mają jakiś regularny wzór lub są w kolejności alfabetycznej, spójrz na użycie
intToUtf8
lubchartr
zastosowanie do sekwencji za pomocąa:b
lub na wbudowanych zestawach literletters
lubLETTERS
. Wbudowany język wzorcówchartr
jest szczególnie wydajny .Dla 1 do 3 znaków lub słów ,
c("a","b","c")
to tylko ogólne rozwiązanie najkrótsza.Jeśli potrzebujesz stałej wektor między 4 a 10 Brak białych znaków lub słów , należy
scan
zstdin
jakfile
arg:Jeżeli
scan
zstdin
nie jest to możliwe, na 6 lub więcej nie białych znaków lub słów użyćscan
ztext
argumentemscan(,"",t="a b c d e f")
.Jeśli potrzebujesz wektora (a) 6 lub więcej znaków dowolnego typu lub (b) 10 lub więcej znaków innych niż spacje , prawdopodobnie jest to metoda
strsplit
viax=el(strsplit("qwertyuiop",""))
.Państwo może być w stanie uciec z poniższym cytatem sztuczki :
quote(Q(W,E,R,T,Y))
, co stwarza, że wypowiedzi. Niektóre funkcje lubiąstrrep
igrep
będą zmuszać to do wektora ciągów! Jeśli to zrobisz, jest to dobre dla dowolnej długości słowa lub wektora znaków od 3 do 11.Nie ma dobrego powodu, aby używać
strsplit
słów przezx=el(strsplit("q w e r t y"," "))
. Zawsze przegrywascan(,"",t="q w e r t y"))
przez stały narzut 5 bajtów.Oto tabela liczb bajtów używanych przez każde podejście do odczytu w wektorze pojedynczych znaków długości
n
. Względne uporządkowanie w każdym wierszu obowiązuje dla znaków lub słów, z wyjątkiem tych,strsplit
w""
których działa tylko na znaki.do. Jeśli potrzebujesz wprowadzić tekst jako matrycę znaków , kilka przepisów, które wydają się krótkie
źródło
scan
matext
argument, który jest bardziej konkurencyjny niżel(strsplit(x," "))
wtedy, gdy potrzebujesz tylko łańcuchów! Wypróbuj online! W przeciwieństwie do twojej ostatniej sugestiiread.csv
.scan
jest lepsze do 5 znaków,el(strsplit(x,""))
jest bardziej konkurencyjne niżscan
dla 6 lub więcej. Wypróbuj online! Nie znalazłem jeszcze dobrego zastosowaniaread.csv
, ale może byłoby przydatne, gdybyś z jakiegoś powodu potrzebował tabeli danych?data.frame
ale może musimy znaleźć / stworzyć wyzwanie, w którym byłoby to pomocne! Możedplyr
stylgroup_by()
isummarize()
rodzaj manipulacji? NIE WIEM.scan(,"")
wydaje się jeszcze lepsze? Wypróbuj online!scan
jest przydatne.Niektóre sposoby znalezienia pierwszego niezerowego elementu tablicy.
Jeśli ma nazwę
x
:Zwraca,
NA
jeśli nie ma niezerowych elementów (w tym kiedyx
jest pusty, ale nieNULL
które błędy).Anonimowo:
Zwraca,
NULL
jeśli nie ma niezerowych elementów lub jest pusty lubNULL
.źródło
NA
jeśli wszystkie elementyx
są zerowe, więc uważam, więc używaj go ostrożnie!Find(c,x)
to ta sama bajtowość: korzyść, której nie trzeba powtarzać (zdefiniować) x, i inne zachowanie, jeśli nie pasuje. TIOFind
jest również trochę bezpieczniejszy, ponieważ działaNULL
, o ile nic więcej nie musi się wydarzyć w wyniku, w którym to przypadku nie jestem pewien, czy powrótNA
lubNULL
jest bezpieczniejszy.sign(Find(c,w))
co spowodowało błędy - musiałem zrobić,Find(c,sign(w))
aby nie popełnić błędu. Myślę, że oba sposoby mają swoje zastosowania.Alternatywy dla
rep()
Czasami
rep()
można tego uniknąć za pomocą operatora jelita grubego:
i recyklingu wektora R.Do powtarzania
n
wartości zerowe, w którymn>0
,0*1:n
jest krótszy niż 3 bajtyrep(0,n)
i!1:n
, tablicaFALSE
jest 4 bajty krótsze, jeśli przypadek zastosowania pozwala na to.Aby powtórzyć
x
n
czasy,x+!1:n
jest o 2 bajty krótszy niżrep(x,n)
. Dlan
nich użyj,!!1:n
jeśli możesz użyć tablicyTRUE
.Aby powtórzyć
x
2n+1
razy, gdzien>=0
,x+0*-n:n
jest krótszy niż 4 bajtyrep(x,2*n+1)
.Oświadczenie
!-n:n
daTRUE
flanki po obu stronachn
FALSE
. To może być używany do generowania nawet liczbę znaków w wywołańintToUtf8()
jeśli pamiętać, że zero jest ignorowany.Modułowa arytmetyka może być użyteczna.
rep
instrukcji zeach
argumentem można czasem uniknąć za pomocą dzielenia liczb całkowitych.Aby wygenerować wektor
c(-1,-1,-1,0,0,0,1,1,1)
,-3:5%/%3
jest o 5 bajtów krótszy niżrep(-1:1,e=3)
.Aby wygenerować wektor
c(0,1,2,0,1,2,0,1,2)
,0:8%%3
zapisuje 4 bajtyrep(0:2,3)
.Czasami transformacje nieliniowe mogą skrócić arytmetykę sekwencji. Mapować
i in 1:15
doc(1,1,3,1,1,3,1,1,3,1,1,3,1,1,3)
wewnątrz instrukcji złożonej, oczywista odpowiedź Golfy jest1+2*(!i%%3)
do 11 bajtów. Jednak3/(i%%3+1)
ma 10 bajtów i będzie piętroć w tej samej sekwencji, więc można go użyć, jeśli potrzebujesz sekwencji do indeksowania tablicy.źródło
Jeśli potrzebujesz użyć funkcji, użyj
pryr::f()
zamiastfunction()
.Przykład:
jest równa
lub nawet lepiej
Ponieważ jeśli jest tylko jeden argument, formals są zgadywane na podstawie kodu .
źródło
function(x,y){x+y}
można go zapisać jakfunction(x,y)x+y
dla tej samej liczby bajtów,pryr::f(x,y,x+y)
ale z większą czytelnością.Przetrwanie wyzwań dotyczących sznurków
Jak wspomniano w innej odpowiedzi
unlist(strsplit(x,split="")
ipaste(...,collapse="")
może być przygnębiające. Ale nie odchodź od nich, są obejścia!utf8ToInt
konwertuje ciąg do wektora,intToUtf8
wykonuje operację odwrotną. Otrzymujesz wektorint
, a nie wektor,char
ale czasem tego właśnie szukasz. Na przykład, aby wygenerować listę-
, lepiej użyćintToUtf8(rep(45,34))
niżpaste(rep("-",34),collapse="")
gsub
jest bardziej przydatny niż inna funkcjagrep
rodziny, gdy działa na jednym łańcuchu. Dwa powyższe podejścia można połączyć, jak w tej odpowiedzi, która skorzystała z porad ovs , Giuseppe i ngm .<
porównuje ciągi leksykograficzne, jak można by się spodziewać.źródło
intToUtf8
ma także drugi argument,multiple = FALSE
który konwertuje zint
s na pojedyncze znaki (łańcuchy o długości jeden), a nie pojedynczy łańcuch, jeśli jest ustawiony naTRUE
.allow_surrogate_pairs = FALSE
, ale nie wiem, co on robi; doktorzy mówią coś o czytaniu dwóch bajtów jako,UTF-16
ale ledwo wiem, co toUTF-8
jest, więc zignoruję to, dopóki ktoś inny nie znajdzie sposobu na grę w golfa.Wskazówki dotyczące ograniczonych problemów ze źródłami:
Znaki w stałych literału R można zastąpić kodami szesnastkowymi, kodami ósemkowymi i kodami Unicode.
np. ciąg
"abcd"
można zapisać:Możemy również mieszać znaki z ósemkowym / szesnastkowym / Unicode i używać razem niektórych kodów ósemkowych i niektórych kodów szesnastkowych, o ile znaki Unicode nie są mieszane ze znakami ósemkowym / szesnastkowym, np .:
Zobaczyć koniec tej sekcji dla dalszych szczegółów.
Ponieważ funkcje można pisać za pomocą literałów łańcuchowych, np.
cat()
Można pisać alternatywnie:możemy również używać kodów ósemkowych, kodów szesnastkowych i Unicode do nazw funkcji:
z jedynym wyjątkiem, że sekwencje Unicode nie są obsługiwane w backtickach ''
Za pomocą okrągłych nawiasów można uniknąć nadużywania operatorów, np .:
Zastosowanie wszystkich trzech lew można znaleźć w tej odpowiedzi
źródło
0xB
i0xb
zwracać11
(nie trzeba wstawiać cudzysłowów ani cudzysłowów).