Answers:
一些技巧:
<-
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
也可以为您节省一些宝贵的字符,但是您将要使用1,2而不是0,1。
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(...)
当然,仅在包中使用一个功能时才有效。
这是微不足道的,但是何时使用@Tommy别名函数的秘诀:如果函数名的长度为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)
甚至更短了一个字节。
一些非常具体的高尔夫技巧:
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)
。任何非零数字均视为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
。如果所有元素都相同,则其标准偏差为零(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
和FALSE
,可以将其自动转换为数字1
和0
,并且可以随意重新定义它们。这意味着您不需要初始化计数器(例如i=0
... i=i+1
),您可以根据需要使用T
或F
(然后直接跳至F=F+1
稍后)。return()
调用。为常用功能定义短别名非常好,例如p=paste
。如果您经常使用一个函数且仅带有两个参数,则插入别名可能会为您节省一些字节。插入别名必须用包围%
。例如:
`%p%`=paste
随后的x%p%y
字节比p(x,y)
。短1个字节。插入别名定义比非插入别名长4个字节p=paste
,因此您必须确保它是值得的。
`+`=paste; x+y
if
,ifelse
和`if`
在R中有多种方法来执行if语句。高尔夫最佳解决方案可能相差很大。
if
用于控制流。它不是向量化的,即只能评估长度为1的条件。它要求else
(可选)返回else值。ifelse
是一个功能。它是向量化的,并且可以返回任意长度的值。它的第三个参数(else值)是必须的。*`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
在某些情况下,我们确实关心else条件,并且希望执行任意代码而不是返回值。在这些情况下,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
块可以返回其中一部分执行的final语句的值。例如,代替
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
是一个数值向量。使用逻辑非运算符!
隐式地将数字重铸为逻辑向量,其中0
is FALSE
和非零值是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在评论中指出了一个六字节的解决方案:
c(x,"")
如果x
是原子的,并且打算将其传递给需要原子向量的函数,则此方法有效。(该函数可能会发出有关忽略参数元素的警告。)
您可以使用上方的时髦索引技巧(例如x[0]=3
),但实际上有一种更快的方法:
x=+x
正运算符隐式地将向量重铸为数字向量,因此TRUE FALSE
变为1 0
。
x=+x
让TRUE
作为1
。
c(x,"")
如果x
您要x
在仅关心第一个元素的函数中使用(可能会抱怨),则可以使用if 原子的。这比便宜1字节x[0]="";
。
有时,我发现自己希望R有一个do-while
循环,因为:
some_code
while(condition){
some_code # repeated
}
太长了,而且太笨拙了。但是,我们可以恢复此行为,并使用该{
功能删除一些字节。
{
和(
是.Primitive
R 中的每个函数。
他们的文档内容为:
实际上,
(
在语义上等同于identityfunction(x) x
,而{
在某种程度上更有趣,请参见示例。
在价值之下
对于
(
,对参数求值的结果。设置了可见性,因此如果在顶层使用,将自动打印。对于
{
,最后一个表达式的结果求值。这具有最后评估的可见性。
(添加了重点)
那么这是什么意思?这意味着do-while循环非常简单
while({some_code;condition})0
因为里面{}
的每个表达式都被求值,并且只有最后一个表达式由返回{
,因此我们可以some_code
在进入循环之前进行求值,并且每次运行condition
都是TRUE
(或正确)。的0
是形成的“真实”的躯体上的1个字节表达的一个while
循环。
滥用outer
将任意函数应用于两个列表的所有组合。想象一个矩阵,其中i,j由第一个args索引,然后您可以为每对定义一个任意函数(i,j)。
使用Map
作为快捷方式mapply
。我的主张是,mapply
在需要访问索引的情况下,它比for循环便宜。滥用R.中的列表结构unlist
非常昂贵。methods::el
让您便宜地取消列出第一个元素。尝试在本地使用具有列表支持的功能。
使用do.call
一概而论任意输入函数调用。
的args累积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
为长度正确的向量,则此操作非常有效。您可以通过调用实际的index / assign函数节省更多"[<-"(cbind(i,j), z)
。这种调用方式返回修改后的矩阵。
使用新行而不是\n
换行符。
压缩行数可以节省您的字节数。内联分配lapply(A<-1:10,function(y) blah)
和函数args分配function(X, U = X^2, V = X^3)
是实现此目的的方法。
"[<-"
R中的一个函数也是如此(并且与我关于SO的古老问题有关)!那是负责诸如之类的操作的基础功能x[1:5] = rnorm(5)
。通过名称调用函数的整洁属性允许您返回修改后的向量。按照顺序,word "[<-"(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
。这将留下一个尾随的零,因此,如果这对您很重要,请使用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
是一个list
或vector
长度大于1的,因为它默认为seq_along(l)
。如果l
可能是长度1
,那就可以seq(a=l)
了。
此外,:
将(带有警告)使用其参数的第一个元素。
删除属性使用c()
上一个array
(或matrix
)会做的一样as.vector
; 通常会删除非名称属性。
阶乘使用gamma(n+1)
比使用短,factorial(n)
并且factorial
始终定义为gamma(n+1)
。
硬币翻转需要50%的时间执行随机任务时,使用时间rt(1,1)<0
要短于runif(1)<0.5
三个字节。
提取/排除元素 head
,tail
通常用于提取数组的前/后几个元素;head(x,-1)
如果您不知道长度,则提取除最后一个元素以外的所有元素,并且比使用负索引更短:
head(x,-1)
x[-length(x)]
x[-sum(x|1)]
rep
” 的标题。其他提示问题每个答案只能有一个提示,我也对此表示衷心的支持!此外,1:n*0
短于Im(1:n)
2个字节,这意味着您的第二个技巧也可以x+0*-n:n
:-)
!1:n
它也是一个n
零数组,具体取决于用例;不过,可以归功于MATL / MATLAB提示问题(可能是Luis Mendo)。
(log(i,b)%/%1):0)
代替floor(log(n,b))+1
?
一些基本概念,但应有些用处:
在控制流语句中,您可能会滥用将不等于零的任何数字都评估为TRUE
,例如:if(x)
等于if(x!=0)
。相反,if(!x)
等效于if(x==0)
。
当使用:
(例如1:5
)生成序列时,可能会滥用幂运算符^
是唯一优先于:
-operator的操作符(与相对+-*/
)的事实。
1:2^2 => 1 2 3 4
这样可以在圆括号上为您节省两个字节,以防您想要例如对n x n
矩阵(1:n^2
)的元素或任何其他可以用指数表示法(1:10^6
)较短表示的整数进行循环。
当然,也可以在矢量化操作上使用相关的技巧+-*/
,尽管最常用的技巧是+-
:
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
您也可以节省一个字节。
编写短函数(可以在一行上表示)时,可以滥用变量分配以将两个字节保存在封闭的花括号中{...}
:
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
二进制和一元运算符的确切优先顺序)。+-/*
优先级低于:
技巧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
例如,参见此答案。
另见这个答案使用[
作为一个两字节,三个参数的操作。
<
优先级低于+
,但*
优先级高于,+
因此您可以将它们链接在一起!
?
到paste
或可以接受两个参数的某个其他函数,则优先顺序意味着您仍然可以通过使用内联分配a<-b?d<-e
。
paste(...,collapse="")
和strsplit
这些是通常的弦乐挑战中的痛苦。有一些解决方法。
Reduce(paste0,letters)
对于-5个字节 paste0(letters,collapse="")
一个2字节的高尔夫,其中有一个包含两个向量的列表c(1,2,3)
,c(4,5,6)
并且想要将它们逐个元素地连接到string "142536"
。操作员滥用为您p=paste0;"^"=Reduce;p^p^r
节省了平时paste0
通话的两个字节。
与其paste0("(.{",n,"})")
构造(例如)20个字节的正则表达式,不如考虑一个正则表达式中的正则表达式:sub(0,"(.{0})",n)
17个字节。
有时(实际上,通常很多),您需要遍历字符或字符串的向量,或将一个单词拆分为字母。有两种常见的用例:一种是需要将字符向量作为函数或程序的输入,另一种是需要事先知道向量并将其存储在代码中的某个地方。
一种。在需要将字符串作为输入并将其拆分为单词或字符的地方。
如果需要单词(特殊情况下包括字符):
如果用换行符0x10
(ASCII 16)分隔单词是可以的,x=scan(,"")
则最好将代码包装在中function(s,x=el(strsplit(s," ")))
。
如果单词可以用任何其他空格分隔,包括多个空格,制表符,换行符等,则可以使用@ngm的double scan技巧:x=scan(,"",t=scan(,""))
。这将扫描的字符串scan
作为text
arg并用空格分隔。
如果需要将输入字符串转换为字符向量:
x=el(strsplit(s,""))
是最短的通用解决方案。该split
参数适用于长度为零的任何内容,包括c()
,{}
等等,因此,如果您碰巧创建了一个零长度的变量,则可以使用它来保存一个字节。
如果可以使用ASCII字符代码,请考虑utf8ToInt
,因为utf8ToInt(x)
它比strsplit
调用短。将它们粘贴回去,intToutf8(utf8ToInt(x))
比短Reduce(paste0,el(strsplit(x,"")))
。
如果您需要分割任意数字串(例如"31415926535"
输入),则可以utf8ToInt(s)-48
在上保存3个字节el(strsplit(s,""))
,前提是您可以使用整数代替字符(通常是这样)。这也比将数字拆分为十进制数字的常用方法要短。
b。您需要事先固定的单词或字符向量。
如果您需要一个具有一定规则模式或字母顺序的单个字符向量,请通过或在内置字母集或上使用intToUtf8
或chartr
应用于序列。内置的模式语言是特别强大。a:b
letters
LETTERS
chartr
对于1到3个字符或单词,c("a","b","c")
是唯一通用的最短解决方案。
如果您需要4到10个非空格字符或单词的固定向量,请使用scan
with stdin
作为file
arg:
f(x=scan(,""))
q
w
e
r
t
y
u
如果无法使用scan
from stdin
,则对于6个或更多的非空白字符或单词,请scan
与text
参数一起使用scan(,"",t="a b c d e f")
。
如果您需要一个(a)6个或更多任何类型的字符或(b)10个或更多非空白字符的向量,则可能要使用strsplit
via x=el(strsplit("qwertyuiop",""))
。
您可能可以摆脱下面的引用技巧:quote(Q(W,E,R,T,Y))
,创建该表达式。某些功能,例如strrep
和,grep
会将其强制为字符串向量!如果这样做,这对于3到11之间的任意长度的单词或字符向量都非常有用。
没有充分的理由在上使用strsplit
单词x=el(strsplit("q w e r t y"," "))
。它总是丢失scan(,"",t="q w e r t y"))
5个字节的固定开销。
这是每种方法用来读取length个字符的向量所使用的字节数的表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 |
C。如果您需要将文本作为字符矩阵输入,那么一些看起来很短的食谱是
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")),"")))
data.frame
但也许我们需要在有帮助的地方找到/创造一个挑战!也许是dplyr
风格group_by()
和summarize()
操纵类型?IDK。
查找数组的第一个非零元素的一些方法。
如果有名称x
:
x[!!x][1]
返回NA
如果没有非零元素(包括时x
是空的,但不是NULL
该错误)。
匿名地:
Find(c, c(0,0,0,1:3))
NULL
如果没有非零元素,或者为空或,则返回NULL
。
NA
如果所有元素x
都为零,这将返回,因此请谨慎使用!
Find
只要它对NULL
结果没有其他影响,它在工作时也会更安全一些,在这种情况下,我不确定返回NA
还是NULL
更安全。
sign(Find(c,w))
,这导致了错误-必须这样做Find(c,sign(w))
才能使其不出错。我认为两种方式都有其用途。
rep()
有时rep()
可以避免使用冒号运算符:
和R的向量循环。
对于重复的n
零,其中n>0
,如果比使用情况短,其中,0*1:n
比rep(0,n)
和短3个字节!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)
复合语句内部,明显的golfy答案是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
与相同的字节数,pryr::f(x,y,x+y)
但可读性更高。
作为另一个答复中提到,unlist(strsplit(x,split="")
并且paste(...,collapse="")
可郁闷。但是,不仅要远离这些,还有解决方法!
intToUtf8
还具有第二个参数multiple = FALSE
,该参数将从int
s 转换为单个字符(长度为一的字符串),而不是设置为的单个字符串TRUE
。
allow_surrogate_pairs = FALSE
,但我不知道它的作用。该文档说了一些有关读取两个字节的内容,UTF-16
但是我几乎不知道这UTF-8
是什么,所以我将忽略它,直到其他人找到打高尔夫球的方法为止。
R文字常量中的字符可以用十六进制代码,八进制代码和unicode代替。
例如,字符串"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"
我们还可以将字符与八进制/十六进制/ unicode混合,并同时使用某些八进制代码和一些十六进制代码,只要unicode字符不与八进制/十六进制混合即可,例如:
# 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`()
我们也可以使用八进制代码,十六进制代码和unicode作为函数名称:
# all equal to cat()
"\143\141\164"()
`\x63\x61\x74`()
'\u63\u61\u74'()
"ca\u74"()
唯一的例外是反引号内不支持unicode序列''
圆括号可以避免虐待操作员,例如:
cat('hello')
# can be written as
`+`=cat;+'hello'
这三个技巧的应用都可以在此答案中找到
0xB
并0xb
返回11
(不需要反引号或引号)。