R 통계 언어로 골프 팁을 찾고 있습니다. R은 아마도 골프를위한 비 전통적인 선택 일 것입니다. 그러나 특정 작업 (시퀀스, 임의성, 벡터 및 목록)을 매우 콤팩트하게 만들고 많은 내장 함수는 매우 짧은 이름 을 가지며 선택적 줄 종결 자 (;)가 있습니다. R의 코드 골프 문제를 해결하는 데 도움이되는 팁과 요령은 무엇입니까?
R 통계 언어로 골프 팁을 찾고 있습니다. R은 아마도 골프를위한 비 전통적인 선택 일 것입니다. 그러나 특정 작업 (시퀀스, 임의성, 벡터 및 목록)을 매우 콤팩트하게 만들고 많은 내장 함수는 매우 짧은 이름 을 가지며 선택적 줄 종결 자 (;)가 있습니다. R의 코드 골프 문제를 해결하는 데 도움이되는 팁과 요령은 무엇입니까?
답변:
몇 가지 팁 :
<-
over 를 사용 하는 것이 좋습니다 =
. 골프의 경우 반대 입장 =
이 짧아 지기 때문에 ...함수를 두 번 이상 호출하면 짧은 별칭을 정의하는 것이 유리합니다.
as.numeric(x)+as.numeric(y)
a=as.numeric;a(x)+a(y)
부분 매칭은 친구가 될 수 있습니다. 특히 함수가 하나의 항목 만 필요한 목록을 반환 할 때 더욱 그렇습니다. 비교
rle(x)$lengths
에rle(x)$l
많은 과제는 입력을 읽어야합니다. scan
사용자는 종종 빈 줄을 입력하여 입력을 종료합니다.
scan() # reads numbers into a vector
scan(,'') # reads strings into a vector
강제가 유용 할 수 있습니다. t=1
보다 훨씬 짧습니다 t=TRUE
. 또는 switch
귀중한 문자를 저장할 수도 있지만 0,1 대신 1,2를 사용하는 것이 좋습니다.
if(length(x)) {} # TRUE if length != 0
sum(x<3) # Adds all the TRUE:s (count TRUE)
함수가 복잡한 것을 계산하고 동일한 핵심 값을 기반으로 다양한 다른 유형의 계산이 필요한 경우 a) 작은 함수로 나누고 b) 필요한 모든 결과를 목록으로 반환하거나 c) 함수에 대한 인수에 따라 다른 유형의 값을 반환합니다.
다른 언어와 마찬가지로 잘 알고 있습니다. R에는 수천 개의 기능이 있으며, 문자가 거의없는 경우 문제를 해결할 수있는 기능이있을 수 있습니다.
애매하지만 유용한 기능들 :
sequence
diff
rle
embed
gl # Like rep(seq(),each=...) but returns a factor
일부 내장 데이터 세트 및 기호 :
letters # 'a','b','c'...
LETTERS # 'A','B','C'...
month.abb # 'Jan','Feb'...
month.name # 'January','Feburary'...
T # TRUE
F # FALSE
pi # 3.14...
로 패키지를 가져 오는 대신을 library
사용하여 패키지에서 변수를 가져옵니다 ::
. 다음을 비교하십시오.
library(splancs);inout(...)
splancs::inout(...)
물론 패키지에서 하나의 단일 기능을 사용하는 경우에만 유효합니다.
이것은 사소한이지만 기능을 앨리어싱의 토미의 트릭 @ 사용하는 경우에 대한 엄지 손가락의 규칙 : 함수 이름의 길이가있는 경우 m
와 사용 n
후 경우에만 별칭 시간을 m*n > m+n+3
지출 별칭을 정의 할 때 (때문에 m+3
다음 당신은 여전히 지출 별명이 사용될 때마다 1). 예를 들면 :
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)
기능의 부작용으로 강요 :
를 사용하는 대신 다음을 사용하여 as.integer
문자열을 정수로 강제 변환 할 수 있습니다 :
.
as.integer("19")
("19":1)[1] #Shorter version using force coercion.
정수, 숫자 등은 다음 paste
대신에 문자를 사용하여 비슷하게 강제 할 수 있습니다 as.character
.
as.character(19)
paste(19) #Shorter version using force coercion.
el("19":1)
은 1 바이트만큼 짧습니다.
매우 구체적인 골프 팁 :
sum(x|1)
보다 짧은 length(x)
만큼 x
, 숫자의 정수, 복잡하거나 논리적이다.rev()
하고 호출 x[1]
보다는 x[length(x)]
(또는 위의 팁을 사용 x[sum(x|1)]
) (또는 tail(x,1)
--- 감사 주세페을!). 이것에 대한 약간의 변형 (두 번째 마지막 요소가 필요한 곳)이 여기에서 볼 수 있습니다 . 벡터를 뒤로 초기화 할 수 없더라도 rev(x)[1]
여전히 짧습니다 x[sum(x|1)]
(및 문자 벡터에서도 작동합니다). 때로는 대신을 rev
사용 n:1
하는 등의 필요조차 없습니다 1:n
.( 여기에서 볼 수 있듯이 ). 데이터 프레임을 행렬로 강제 변환하려면을 사용하지 마십시오 as.matrix(x)
. 조옮김의 조옮김 t(t(x))
.
if
공식적인 기능입니다. 예를 들어, "if"(x<y,2,3)
보다 짧습니다 if(x<y)2 else 3
(물론 3-(x<y)
둘 중 하나보다 짧습니다). 이런 식으로 공식화하기 위해 추가 괄호 쌍이 필요하지 않은 경우에만 문자를 저장합니다.
동일하지 않은 숫자 객체를 테스트하는 if(x-y)
경우보다 짧습니다 if(x!=y)
. 0이 아닌 숫자는로 간주됩니다 TRUE
. 평등을 테스트하는 경우 대신 if(x==y)a else b
시도하십시오 if(x-y)b else a
. 또한 이전 요점을 참조하십시오.
이 기능 el
은 목록에서 항목을 추출해야 할 때 유용합니다. 가장 일반적인 예는 아마도 strsplit
: el(strsplit(x,""))
이상 적은 바이트입니다 strsplit(x,"")[[1]]
.
( 여기에 사용됨 ) 벡터 확장은 문자를 절약 할 수 있습니다. 벡터 v
길이가 길면 오류없이 n
할당 할 수 있습니다 v[n+1]
. 첫 번째 열 계승을 인쇄하고 싶었 예를 들어, 당신은 할 수 : v=1;for(i in 2:10)v[i]=v[i-1]*i
보다는 v=1:10:for(...)
(언제나처럼, 또 다른, 더 나은 방법이 있지만 : cumprod(1:10)
)
때로는 텍스트 기반 문제 (특히 2D 문제)의 plot
경우 텍스트보다 텍스트가 더 쉽습니다 cat
. 어떤 문자가 그려 지는지 pch=
를 plot
제어하는 인수 . 이것은 pc=
바이트를 절약하기 위해 단축 될 수 있습니다 (경고를 줄 것입니다). 여기에 예가 있습니다 .
숫자를 바닥에 쓰려면을 사용하지 마십시오 floor(x)
. x%/%1
대신 사용하십시오 .
숫자 형 벡터 나 정수형 벡터의 요소가 모두 같은지 테스트하려면 sd
과 같은 장황한 것이 아니라 종종 사용할 수 있습니다 all.equal
. 모든 요소가 동일하면 표준 편차가 0 ( FALSE
) 이고 표준 편차가 양수 ( TRUE
)입니다. 여기에 예가 있습니다 .
정수 입력이 필요한 일부 함수는 실제로 필요하지 않습니다. 예를 들어, seq(3.5)
리턴합니다 1 2 3
( :
연산자도 마찬가지입니다 ). 이것은 호출을 피할 수 floor
있으며 때로는 /
대신 대신 사용할 수 있음을 의미합니다 %/%
.
tail(v,1)
rev(v)[1]
"어레이의 마지막 요소"골프 팁과 동일한 길이 입니다.
read.csv(t="a,b,c",,F)
보다 짧습니다 el(strsplit("a,b,c",","))
.
T
하고 F
. 기본적으로 TRUE
and로 평가되며 FALSE
숫자 1
및 로 자동 변환 0
될 수 있으며 마음대로 재정의 할 수 있습니다. 즉, 카운터를 초기화 할 필요가 없습니다 (예 : i=0
... i=i+1
) T
또는 F
필요에 따라 사용 하거나 F=F+1
나중에 바로 이동할 수 있습니다 .return()
호출 된 객체를 반환하므로 명시적인 호출이 필요하지 않습니다 .일반적으로 사용되는 함수에 대한 짧은 별칭을 정의하는 것이 좋습니다 p=paste
. 함수를 많이 사용하고 정확히 두 개의 인수 를 사용하면 별칭이 붙으면 일부 바이트가 절약 될 수 있습니다. 삽입 별명은로 묶어야합니다 %
. 예를 들면 다음과 같습니다.
`%p%`=paste
그리고 이후 x%p%y
1 바이트보다 짧은 것 p(x,y)
입니다. 그래도 별명 정의는 비고 정보 다 4 바이트 더 길 p=paste
므로 그 가치가 있는지 확인해야합니다.
`+`=paste; x+y
if
, ifelse
및`if`
R.에서 if-statement를 수행하는 방법은 여러 가지가 있습니다. 골프 최적화 솔루션은 크게 다를 수 있습니다.
if
제어 흐름입니다. 벡터화되지 않습니다. 즉, 길이 1의 조건 만 평가할 수 있습니다. else
선택적으로 else 값을 반환해야합니다.ifelse
함수입니다. 벡터화되어 임의 길이의 값을 반환 할 수 있습니다. 세 번째 주장 (다른 가치)은 의무적입니다. *`if`
와 구문이 동일한 함수 ifelse
입니다. 벡터화되지 않았으며 반환 인수가 의무화되지 않았습니다.* 기술적으로 의무적 인 것은 아닙니다. ifelse(TRUE,x)
잘 작동하지만 세 번째 인수가 비어 있고 조건이로 평가되면 오류가 발생합니다 FALSE
. 따라서 조건이 항상 확실하다고 확신하는 경우에만 사용하는 것이 안전하며 TRUE
, 그러한 경우 if 문으로 귀찮게하는 이유는 무엇입니까?
이들은 모두 동등합니다 :
if(x)y else z # 13 bytes
ifelse(x,y,z) # 13 bytes
`if`(x,y,z) # 11 bytes
else
코드에서 직접 문자열을 사용하는 경우 공백 이 필요하지 않습니다.
if(x)"foo"else"bar" # 19 bytes
ifelse(x,"foo","bar") # 21 bytes
`if`(x,"foo","bar") # 19 bytes
지금까지 `if`
입력을 벡터화하지 않은 한 승자가 될 것으로 보입니다. 그러나 else 조건에 관심이없는 경우는 어떻습니까? 조건이 인 경우 일부 코드 만 실행하려고한다고 가정 해보십시오 TRUE
. 한 줄의 코드만으로도 if
가장 좋습니다.
if(x)z=f(y) # 11 bytes
ifelse(x,z<-f(y),0) # 19 bytes
`if`(x,z<-f(y)) # 15 bytes
여러 줄의 코드에서 if
여전히 승자가됩니다.
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
이 우리가 가능성이기도 않는 다른 조건에 대한 관심은, 우리는 임의의 코드를 실행하는 대신 값을 반환 할 위치. 이러한 경우, if
및 `if`
바이트 수에 동일합니다.
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
ifelse
길이가 1보다 큰 입력을 사용하는 경우 사용하십시오 .
많은 코드 줄을 실행하지 않고 간단한 값을 반환하는 경우 `if`
함수를 사용하는 것이 full if
... else
문 보다 짧을 수 있습니다.
언제 단일 값을 원하면을 TRUE
사용하십시오 if
.
임의의 코드를 실행 `if`
하고 if
일반적 바이트 개수의 관점에서 동일하다; 나는 if
주로 읽기 쉽기 때문에 추천 합니다.
변수를 함수에 대한 인수로 제공하면서 동시에 현재 환경에 변수를 지정할 수 있습니다.
sum(x <- 4, y <- 5)
x
y
a를 부분 집합하고 data.frame
조건이 여러 열에 의존 data.frame
하는 경우 with
(또는 subset
) 를 사용하여 이름을 반복하지 않아도 됩니다.
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,])
대신에
d[d$a=='b' & d$b==2 & d$c==5 & d$e==8,]
물론 이것은 참조 data.frame
길이가 길이를 초과하는 경우에만 문자를 저장합니다.with(,)
if...else
블록은 블록의 일부가 실행되는 최종 명령문의 값을 리턴 할 수 있습니다. 예를 들어
a <- 3
if (a==1) y<-1 else
if (a==2) y<-2 else y<-3
당신은 쓸 수 있습니다
y <- if (a==1) 1 else
if (a==2) 2 else 3
f <- function(a,b) cat(a,b)
, 다음 f(a <- 'A', b <- 'B')
과 동일하지 않습니다 f(b <- 'B', a <- 'A')
.
기능은 as.character
, as.numeric
그리고 as.logical
너무 바이트 무겁습니다. 그것들을 다듬어 봅시다.
x
숫자 형 벡터 라고 가정하십시오 . 논리 not 연산자를 사용하면 !
숫자가 암시 적으로 논리 벡터로 다시 캐스팅 됩니다 . 여기서 0
is FALSE
및 0이 아닌 값은 TRUE
입니다. !
그런 다음 반전시킵니다.
x=!x
x=0:3;x=!x
을 반환합니다 TRUE FALSE FALSE FALSE
.
이것은 재미있는 것입니다. ( 이 트윗 에서)
x[0]=''
R 은 클래스 의 인 벡터 x
를 업데이트하고 있음을 알았습니다 . 따라서 새로운 데이터 포인트와 호환되도록 클래스에 캐스트 됩니다 . 다음으로, 넣어 간다 적절한 장소에 ...하지만 인덱스 (이 트릭도 함께 작동 존재하지 않는 , , , , 등). 결과적으로 클래스에서만 수정됩니다.''
character
x
character
''
0
Inf
NaN
NA
NULL
x
x=1:3;x[0]=''
반환 "1" "2" "3"
및 x=c(TRUE,FALSE);x[0]=''
반환 "TRUE" "FALSE"
.
작업 공간에 이미 문자 오브젝트가 정의되어 있으면 ''
바이트를 저장하는 대신이 를 사용할 수 있습니다 . 예 x[0]=y
!
J.Doe 는 주석에서 6 바이트 솔루션을 지적했습니다.
c(x,"")
x
원자 인 경우 원자 벡터가 필요한 함수에 전달하려는 경우 작동합니다 . 이 함수는 인수의 요소를 무시하는 것에 대한 경고를 표시 할 수 있습니다.
위에서 펑키 인덱싱 트릭을 사용할 수 x[0]=3
있지만 실제로 더 빠른 방법이 있습니다.
x=+x
양의 연산자는 암시 적으로 벡터를 숫자 벡터로 다시 캐스팅하므로이 TRUE FALSE
됩니다 1 0
.
x=+x
로 유지 TRUE
하는 것 1
입니다.
c(x,"")
경우 x
원자, 당신은 다음 사용하는 거라고 제공하는 x
전용 (이 불평 수) 첫 번째 요소에 대한 관심 함수에서. 보다 1 바이트 저렴합니다 x[0]="";
.
때때로, 나는 R이 do-while
루프를 갖기를 바랐다.
some_code
while(condition){
some_code # repeated
}
너무 길고 골치 거리가 아닙니다. 그러나이 동작을 복구하고 {
함수 의 힘으로 일부 바이트를 줄일 수 있습니다 .
{
그리고 (
각각 .Primitive
R. 함수
그들에 대한 문서는 다음과 같습니다.
사실상
(
신원과 의미 적으로 동일function(x) x
하지만{
약간 더 흥미 롭습니다 (예 참조).
그리고 가치 아래
의 경우
(
인수를 평가 한 결과입니다. 가시성이 설정되어 있으므로 최상위 수준에서 사용하면 자동 인쇄됩니다.에 대해
{
, 마지막 표현식의 결과가 평가되었습니다 . 이것은 마지막 평가의 가시성을 가지고 있습니다.
(강조 추가)
이것이 무엇을 의미합니까? 그것은 do-while 루프가 간단하다는 것을 의미합니다.
while({some_code;condition})0
표현식 안에 있기 때문에 {}
각각 평가, 만 마지막은 에 의해 반환 {
우리가 평가할 수 있도록 some_code
루프에 들어가기 전에, 그것은 때마다 실행 condition
이다 TRUE
(또는 truthy을). 이것은 루프 0
의 "실제"본문을 형성하는 많은 1 바이트 표현식 중 하나입니다 while
.
outer
두 목록의 모든 조합에 임의의 기능을 적용하기위한 남용 . 첫 번째 인수로 인덱스 된 i, j를 갖는 행렬을 상상 한 다음 각 쌍에 대해 임의의 함수 (i, j)를 정의 할 수 있습니다.
에 Map
대한 바로 가기로 사용하십시오 mapply
. 내 주장은 mapply
인덱스에 액세스 해야하는 상황에서 for 루프보다 저렴하다는 것입니다. R의 목록 구조를 남용하는 unlist
것은 비싸다. methods::el
첫 번째 요소를 저렴하게 나열 해제 할 수 있습니다. 기본적으로 목록 지원 기능을 사용하십시오.
do.call
임의의 입력으로 함수 호출을 일반화하는 데 사용 합니다.
에 대한 누적 인수 Reduce
는 코드 골프에 매우 도움이됩니다.
로 줄 단위로 콘솔에 쓰는 cat(blah, "\n")
것이보다 저렴합니다 write(blah, 1)
. 경우에 따라 "\ n"으로 하드 코딩 된 문자열이 더 저렴할 수 있습니다.
함수에 기본 인수가있는 경우 function (,, n-arg)을 사용하여 n 번째 인수를 직접 지정할 수 있습니다. 예 : seq(1, 10, , 101)
일부 함수에서는 부분 인수 일치가 지원됩니다. 예 : seq(1, 10, l = 101)
.
문자열 조작과 관련된 문제가있는 경우 뒤로 버튼을 누르고 다음 질문을 읽으십시오. strsplit
R 골프를 망치는 것은 하나의 책임입니다.
이제 2018에서 새로 발견 된 팁
A[cbind(i,j)] = z
행렬을 조작하는 좋은 방법이 될 수 있습니다. 이 연산은 i, j, z
올바른 길이의 벡터로 디자인한다고 가정하면 매우 바이트 효율적 입니다. 실제 인덱스 / 할당 기능을 호출하여 더 많은 비용을 절약 할 수 있습니다 "[<-"(cbind(i,j), z)
. 이 호출 방식은 수정 된 행렬을 반환합니다.
\n
줄 바꿈 대신 새 줄을 사용하십시오 .
줄 카운트를 줄이면 바이트를 절약 할 수 있습니다. 인라인 할당 lapply(A<-1:10,function(y) blah)
및 함수 인수 할당 function(X, U = X^2, V = X^3)
이이를 수행하는 방법입니다.
그래서 "[<-"
R의 함수이다 (그리고 관련이 SO에 내 고대 질문 )! 이는 다음과 같은 작업을 담당하는 기본 기능 x[1:5] = rnorm(5)
입니다. 이름으로 함수를 호출하는 깔끔한 속성을 사용하면 수정 된 벡터를 반환 할 수 있습니다. 순서대로 단어 "[<-"(x, 1:5, normr(5))
는 수정 된 x를 반환한다는 점을 제외하고 위 코드와 거의 동일합니다. 관련된 "length <-", "names <-", "anything <-"은 모두 수정 된 출력을 리턴합니다.
"[<-"
수정 된 배열 / 행렬 / 무엇이든 반환 할 것이기 때문에 사용하는 것이 "팁"응답에 합당 하다고 생각 합니다.
인라인으로 값 저장 : 다른 사람들은 순서대로 값을 전달하고 다른 곳에서 사용하기 위해 값을 할당 할 수 있다고 언급했습니다.
sum(x<- 1:10, y<- seq(10,1,2))
그러나 같은 줄에서 사용하기 위해 값을 인라인으로 저장할 수도 있습니다 !
예를 들어
n=scan();(x=1:n)[abs(x-n/2)<4]
에서 읽고 stdin
변수 x=1:n
를 만든 다음 x
해당 값 을 사용하여 색인을 생성합니다 x
. 때때로 바이트를 절약 할 수 있습니다.
빈 벡터의 별칭 모두 반환 {}
되는 빈 벡터 c()
로 사용할 수 있습니다 NULL
.
기본 변환n
밑이 10 인 정수는 을 사용 n%/%10^(0:nchar(n))%%10
합니다. 이것은 후행 0을 남기므로 중요한 n%/%10^(1:nchar(n)-1)%%10
경우 배열 인덱싱보다 짧으므로 사용 하십시오. floor(log(n,b))+1
대신에 다른베이스에 적용 할 수 있습니다.nchar(n)
사용 seq
과:
: 대신 사용하는 것보다 1:length(l)
(또는 1:sum(x|1)
), 당신이 사용할 수있는 seq(l)
만큼 l
A는 list
나 vector
에 대한 기본값으로, 1보다 큰 길이 seq_along(l)
. l
잠재적으로 length 1
일 수 있으면 seq(a=l)
트릭을 수행합니다.
또한 :
will은 (경고와 함께) 인수의 첫 번째 요소를 사용합니다.
속성 제거 하여 c()
온 array
(또는 matrix
과 동일 할 것) as.vector
; 일반적으로 이름이 아닌 속성을 제거합니다.
계승 사용은 gamma(n+1)
사용하는 것보다 짧은 factorial(n)
과 factorial
같이 정의된다 gamma(n+1)
어쨌든.
동전 뒤집기 50 %의 임의 작업을 수행해야 할 경우 사용 시간 이 3 바이트 rt(1,1)<0
보다 짧습니다 runif(1)<0.5
.
요소를 제외 / 추출 head
과 tail
종종 어레이의 제 / 최후의 요소를 추출하는 것이 유용하다; head(x,-1)
길이를 모르는 경우 마지막 요소를 제외한 모든 요소를 추출하고 음수 색인을 사용하는 것보다 짧습니다.
head(x,-1)
x[-length(x)]
x[-sum(x|1)]
rep
. 다른 팁 질문에는 답변 당 하나의 팁 제한이 있으며,이 질문에 대해서도 진심으로 보증합니다! 또한 2 바이트 1:n*0
보다 짧으므로 Im(1:n)
두 번째 트릭도 가능합니다 x+0*-n:n
:-)
!1:n
것은 n
사용 사례에 따라 0 의 배열입니다 . 그래도 MATL / MATLAB 팁 질문 (아마도 Luis Mendo)에게 감사드립니다.
(log(i,b)%/%1):0)
않고 floor(log(n,b))+1
?
몇 가지 기본 개념이지만 다소 유용해야합니다.
제어 흐름 설명에서 0이 아닌 숫자는 다음과 같이 평가됨을 남용 할 수 있습니다 . TRUE
예를 들면 다음 if(x)
과 같습니다 if(x!=0)
. 반대로, if(!x)
와 같습니다 if(x==0)
.
:
(예를 들어 1:5
)를 사용하여 시퀀스를 생성 할 때 지수 연산자 ^
가-연산자보다 우선하는 유일한 연산자라는 사실을 남용 할 수 있습니다 :
(와 반대로 +-*/
).
1:2^2 => 1 2 3 4
예를 들어 n x n
행렬 ( 1:n^2
) 또는 지수 표기법 ( 1:10^6
)을 사용하여 더 짧은 방식으로 표현할 수있는 다른 정수 의 요소를 반복하려는 경우 일반적으로 사용해야하는 괄호에 2 바이트가 절약됩니다 .
물론 +-*/
가장 일반적으로 적용되지만 벡터화 된 연산에도 관련 트릭을 사용할 수 있습니다 +-
.
for(i in 1:(n+1)) can instead be written as for(i in 0:n+1)
이것은 +1
벡터화 되어 벡터 1
를 0:n
생성 하는 각 요소에 추가 되기 때문에 작동 합니다 1 2 ... n+1
. 마찬가지로 0:(n+1) == -1:n+1
1 바이트도 절약합니다.
짧은 함수 (한 줄로 표현할 수 있음)를 작성할 때 변수 할당을 남용하여 묶는 중괄호에 2 바이트를 절약 할 수 있습니다 {...}
.
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")}
이것이 항상 특정 문제의 규칙을 준수하지는 않을 수 있습니다.
^
벡터화되어 우선 순위가 높습니다 :
(즉, :
대괄호가 명시 적으로 반대를 나타내지 않는 한 이전에 실행 됩니다 ( ?Syntax
이진 및 단항 연산자의 정확한 우선 순위 참조 ). 따라서 트릭 n ° 3 +-/*
보다 우선 순위가 낮은 이진에 대해서도 마찬가지입니다 :
.
R 연산자는 파서에 의해 특별한 처리를받는 함수일뿐입니다. 예를 들어 <
실제로는 두 변수의 함수입니다. 이 두 줄의 코드는 동일한 작업을 수행합니다.
x < 3
`<`(x, 3)
연산자에 다른 함수를 다시 할당 할 수 있으며 파서는 연산자 우선 순위를 포함하여 여전히 수행하지만 최종 함수 호출은 원래 함수가 아닌 새로운 함수 호출입니다. 예를 들면 다음과 같습니다.
`<`=rep
이제이 두 줄의 코드가 같은 일을합니다.
rep("a", 3)
"a"<3
우선 순위가 존중되어 다음과 같은 결과가 나타납니다.
"a"<3+2
#[1] "a" "a" "a" "a" "a"
예를 들어이 답변 과 연산자 우선 순위 페이지를 참조하십시오 . 부작용으로 귀하의 코드는 골프 언어로 작성된 코드처럼 암호가됩니다.
일부 연산자 는 하나 또는 두 개의 매개 변수를 좋아 +
하고 -
받아 들일 수 있으므로 다음과 같은 작업을 수행 할 수도 있습니다.
`-`=sample
set.seed(1)
-5 # means sample(5)
#[1] 2 5 4 3 1
5-2 # means sample(5, 2)
#[1] 5 4
예를 들어이 답변을 참조하십시오 .
2 바이트, 3 인수 연산자로 사용하려면 이 답변 을 참조하십시오 [
.
<
보다 낮은 우선 순위를 가지고 +
있지만, *
보다 높은 우선 순위를 가지고 +
그래서 당신은 잠재적으로 그들을 함께 체인 수 있습니다!
?
에 paste
또는 두 개의 인수를 취할 수있는 몇 가지 다른 기능은, 우선 순위 순서가 여전히 통해 인라인 할당을 사용할 수 있다는 것을 의미합니다 a<-b?d<-e
.
[
3 요소 별명 (2 바이트)으로 추가해야합니다 . 나는 종종 같은 것들에 대한 것이 도움이 outer
물론 당신이 확인해야하지만 (그리고 지속적으로 잊어!), 당신이 실제로 사용할 필요가 없습니다 [
. 별명 선택을 돕기 위해 운영자 우선 순위 페이지 에 링크하는 것도 도움이 될 것 입니다.
paste(...,collapse="")
와strsplit
이것은 일반적인 문자열 도전에서 고통입니다. 몇 가지 해결 방법이 있습니다.
Reduce(paste0,letters)
-5 바이트 paste0(letters,collapse="")
2 바이트 골프 두 개의 벡터를 포함하는 목록을 c(1,2,3)
과 c(4,5,6)
하고 문자열로 그들에게 요소 현명한 연결할 싶어 "142536"
. 운영자 악용으로 p=paste0;"^"=Reduce;p^p^r
일반적인 paste0
호출 에서 2 바이트를 절약 할 수 있습니다 .
paste0("(.{",n,"})")
정규식을 20 바이트로 구성 하는 대신 정규식에서 sub(0,"(.{0})",n)
17 바이트를 고려하십시오.
때로는 (실제로는 매우 자주) 문자 또는 문자열로 구성된 벡터를 반복하거나 단어를 문자로 분할해야 할 때가 있습니다. 두 가지 일반적인 사용 사례가 있습니다. 하나는 함수 또는 프로그램의 입력으로 문자 벡터를 가져와야하고 다른 하나는 사전에 벡터를 알고 어딘가에 코드에 저장해야하는 것입니다.
에이. 문자열을 입력 으로 받아 단어 나 문자 로 분할 해야하는 경우 .
단어 가 필요한 경우 (특수 문자로 문자 포함) :
0x10
단어를 구분 하는 줄 바꿈 (ASCII 16)이 정상이면 x=scan(,"")
코드를 줄 바꿈하는 것이 좋습니다 function(s,x=el(strsplit(s," ")))
.
단어에 의해 분리 될 수있는 경우 다른 공백 줄 바꿈 등 여러 공백, 탭, 포함, 당신은 NGM의 @ 사용할 수있는 이중 스캔 트릭 : x=scan(,"",t=scan(,""))
. 이에 문자열에서 스캔을 제공 scan
는 AS text
인수와 공백하여 분리한다.
두 번째 인수는 scan
모든 문자열이 될 수 있으므로 문자열을 만든 경우 바이트를 저장하기 위해 재활용 할 수 있습니다 .
입력 문자열을 문자 로 구성된 벡터 로 변환해야하는 경우 :
x=el(strsplit(s,""))
가장 짧은 일반적인 솔루션입니다. split
인수를 포함한 길이가 0의 아무것도 작동 c()
, {}
당신이 길이가 0 인 변수를 만든 일이 있다면, 당신은 바이트를 저장하는 데 사용할 수 있도록 등.
당신이 ASCII 문자 코드로 작업 할 수있는 경우, 고려 utf8ToInt
하기 때문에, utf8ToInt(x)
댄 짧은 strsplit
전화. 다시 붙여 넣으려면 intToutf8(utf8ToInt(x))
보다 짧습니다 Reduce(paste0,el(strsplit(x,"")))
.
"31415926535"
입력 과 같이 임의의 숫자 문자열을 분리 해야하는 경우 종종 문자처럼 정수 자리를 사용할 수있는 경우 utf8ToInt(s)-48
3 바이트를 절약 el(strsplit(s,""))
할 수 있습니다. 이것은 숫자를 10 진수로 나누기위한 일반적인 레시피보다 짧습니다.
비. 사전에 단어 나 문자로 고정 된 벡터 가 필요한 경우 .
당신은 사용하여보고, 몇 가지 규칙적인 패턴이 있거나 알파벳 순서에있는 단일 문자의 벡터가 필요한 경우 intToUtf8
또는 chartr
를 통해 시퀀스에 적용 a:b
하거나 문자 세트에 내장에 letters
이상 LETTERS
. 내장 된 패턴 언어 chartr
는 특히 강력 합니다.
를 들어 1 ~ 3 문자 나 단어 , c("a","b","c")
유일한 일반 짧은 솔루션입니다.
당신의 고정 된 벡터가 필요한 경우 4과 10 사이 공백 이외의 문자 나 단어를 사용 scan
하여 stdin
는 AS file
ARG :
f(x=scan(,""))
q
w
e
r
t
y
u
경우 scan
에서은 stdin
을 위해, 할 수 없습니다 6 개 이상의 비 공백 문자 나 단어 사용 scan
와 text
인수 scan(,"",t="a b c d e f")
.
당신의 벡터를해야하는 경우 (가) 모든 유형의 6 개 이상의 문자 또는 (b) 10 이상의 공백이 아닌 문자 , strsplit
를 통해 x=el(strsplit("qwertyuiop",""))
아마 갈 수있는 방법입니다.
당신은 할 수있다 멀리 얻을 수있을 다음 인용 트릭 : quote(Q(W,E,R,T,Y))
표현한다는 생성한다. 일부 기능은 좋아 strrep
하고, grep
문자열의 벡터이 강요합니다! 그렇게하면 3에서 11 사이의 단어 나 문자형 벡터에 적합합니다.
strsplit
via를 통해 단어를 사용해야 할 이유가 없습니다 x=el(strsplit("q w e r t y"," "))
. 항상 scan(,"",t="q w e r t y"))
5 바이트의 고정 오버 헤드로 손실됩니다 .
다음은 길이가 단일 문자 인 벡터를 읽는 데 각 방법에서 사용하는 바이트 수의 표입니다 n
. 각 행 내에서 상대적인 순서를 제외하고, 문자 나 단어에 대해 유효 strsplit
에 ""
문자 만 작동한다.
| 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 |
씨. 텍스트를 문자 행렬로 입력해야하는 경우 짧게 보이는 몇 가지 레시피는 다음과 같습니다.
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")),"")))
scan
문자열 만 필요한 경우 text
보다 경쟁력 있는 인수 el(strsplit(x," "))
가 있습니다! 온라인으로 사용해보십시오! 에 대한 마지막 제안과는 반대로 read.csv
.
scan
는 최대 5 자 el(strsplit(x,""))
이상 scan
이며, 6 명 이상 보다 경쟁력이 있습니다. 온라인으로 사용해보십시오! 아직에 대한 좋은 사용법을 찾지 못했지만 read.csv
어떤 이유로 데이터 테이블이 필요한 경우 유용 할 수 있습니까?
data.frame
못했지만 도움이 될만한 도전을 찾아야 할 수도 있습니다! 아마 dplyr
스타일 group_by()
과 summarize()
조작의 유형? IDK.
scan(,"")
것이 여전히 더 나은 것 같습니까? 온라인으로 사용해보십시오!
배열의 첫 번째 0이 아닌 요소를 찾는 몇 가지 방법.
이름이 있다면 x
:
x[!!x][1]
NA
0이 아닌 요소가없는 경우를 반환 합니다 ( x
비어 있지만 NULL
오류가 없는 경우 포함 ).
익명으로 :
Find(c, c(0,0,0,1:3))
NULL
0이 아닌 요소가 없거나 비어 있거나없는 경우를 반환 합니다 NULL
.
NA
모든 요소 x
가 0 이면 돌아올 것이라고 생각합니다.주의해서 사용하십시오!
Find
또한 NULL
결과에 다른 일이 발생하지 않는 한 작동하는 동안 조금 더 안전합니다.이 경우 반환 NA
또는 NULL
더 안전 한지 확실하지 않습니다 .
sign(Find(c,w))
오류는 오류가 발생하지 Find(c,sign(w))
않도록해야했습니다. 나는 두 가지 방법이 모두 사용한다고 생각합니다.
rep()
rep()
콜론 연산자 :
와 R의 벡터 재활용으로 때로는 피할 수 있습니다 .
반복을 위해 n
, 제로를 여기서 n>0
, 0*1:n
보다 3 바이트 짧다 rep(0,n)
및 !1:n
배열이 FALSE
사용 사례가 허용하는 경우, 4 바이트 짧다.
반복 x
n
시간 x+!1:n
은보다 2 바이트 짧습니다 rep(x,n)
. 대한 n
사람, 사용 !!1:n
하면의 배열을 사용할 수 있는지 TRUE
.
반복합니다 x
2n+1
번 n>=0
, x+0*-n:n
4 바이트보다 짧은입니다 rep(x,2*n+1)
.
성명서 !-n:n
에는 TRUE
양쪽에 측면이 n
FALSE
있습니다. 이것은 사용할 수 있습니다 생성 도 호출 문자의 수를 intToUtf8()
당신이 제로가 무시됩니다 것을 기억합니다.
모듈 식 산술이 유용 할 수 있습니다. 정수 나누기를 사용하여 인수가있는 rep
명령문을 each
피할 수 있습니다.
벡터를 생성하려면 c(-1,-1,-1,0,0,0,1,1,1)
, -3:5%/%3
5 바이트 짧다 rep(-1:1,e=3)
.
벡터를 생성하려면 c(0,1,2,0,1,2,0,1,2)
, 0:8%%3
4 바이트를 저장합니다 rep(0:2,3)
.
때때로 비선형 변환은 시퀀스 산술을 단축시킬 수 있습니다. 복합 명령문 내부에 맵핑 i in 1:15
하기 c(1,1,3,1,1,3,1,1,3,1,1,3,1,1,3)
위해 명백한 골치 아픈 대답은 1+2*(!i%%3)
11 바이트입니다. 그러나 3/(i%%3+1)
인 10 바이트 같은 순서로, 의지의 바닥을, 그래서 당신은 배열의 인덱스 순서를해야 할 경우 사용할 수 있습니다.
함수를 사용해야 할 때는 pryr::f()
대신을 사용하십시오 function()
.
예:
function(x,y){x+y}
에 해당
pryr::f(x,y,x+y)
또는 더 나은
pryr::f(x+y)
인수가 하나만 있으면 코드에서 형식을 추측합니다 .
function(x,y){x+y}
같이 쓸 수있다 function(x,y)x+y
와 같은 bytecount가에 대한 pryr::f(x,y,x+y)
하지만 더 가독성.
바와 같이 다른 답변에 언급, unlist(strsplit(x,split="")
및 paste(...,collapse="")
우울이 될 수 있습니다. 그러나 이것들로부터 멀리 떨어지지 마십시오. 해결 방법이 있습니다!
utf8ToInt
문자열을 벡터로 변환 intToUtf8
하고 역 연산을 수행합니다. 당신의 벡터지고있어 int
의 아닌 벡터를 char
하지만 때로는 이것이 당신이 찾고있는 것입니다. 인스턴스의 목록을 생성하기 위해 -
,보다 효율적으로 사용하는 intToUtf8(rep(45,34))
것보다를paste(rep("-",34),collapse="")
gsub
grep
단일 문자열에서 작동 할 때 제품군 의 다른 기능보다 더 유용 합니다. 위의 두 가지 접근 방식은 이 답변 에서와 같이 결합되어 ovs , Giuseppe 및 ngm 의 조언을 활용할 수 있습니다.<
문자열을 사전 식으로 예상대로 비교합니다.intToUtf8
또한 multiple = FALSE
로 int
설정된 경우 단일 문자열이 아닌 s에서 개별 문자 (길이 1 문자열) 로 변환되는 두 번째 인수 가 TRUE
있습니다.
allow_surrogate_pairs = FALSE
이 있지만 그것이 무엇인지 모르겠습니다. 문서는 2 바이트를 읽는 것에 대해 무언가를 UTF-16
말하지만 나는 그것이 무엇인지 거의 알지 못 UTF-8
하기 때문에 누군가가 그것을 가지고 골프를 할 수있는 방법을 찾을 때까지 나는 그것을 무시할 것입니다.
R 리터럴 상수의 문자는 16 진 코드, 8 진 코드 및 유니 코드로 대체 될 수 있습니다.
예를 들어 문자열을 "abcd"
작성할 수 있습니다.
# 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"
유니 코드 문자가 8 진수 / 16 진수와 혼합되지 않는 한 문자를 8 진수 / 16 진수 / 유니 코드와 혼합하고 일부 8 진수 코드와 16 진수 코드를 함께 사용할 수도 있습니다.
# 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"
자세한 내용 은이 섹션의 끝 부분 을 참조하십시오.
문자열 리터럴을 사용하여 함수를 작성할 수 있으므로 cat()
대체적으로 작성할 수 있습니다.
'cat'()
"cat"()
`cat`()
함수 이름에 8 진 코드, 16 진 코드 및 유니 코드를 사용할 수 있습니다.
# all equal to cat()
"\143\141\164"()
`\x63\x61\x74`()
'\u63\u61\u74'()
"ca\u74"()
유니 코드 시퀀스가 백틱 내에서 지원되지 않는 유일한 예외는``
작업자를 학대하는 둥근 괄호는 다음과 같이 피할 수 있습니다.
cat('hello')
# can be written as
`+`=cat;+'hello'
이 답변에서 세 가지 트릭을 모두 적용 할 수 있습니다.
0xB
및 0xb
반환 11
(역 따옴표 또는 따옴표 필요 없음).