Answers:
?d
到?~
1.8。$><<"string"
则比print"string"
。$<.map{|l|...}
则比短while l=gets;...;end
。你也可以用$<.read
它一次阅读所有内容。$<
并且gets
文件名位于中,则将从文件中读取文件而不是stdin文件ARGV
。因此,要重新实现golfiest方式cat
是:$><<$<.read
。cat
是将ruby文件完全空白(0字节),并坚持应从带有-p
标志的命令行运行它。
puts *$<
☺
或的想法来超越126 ♫
,或者如果您足够疯狂的话:?﷽.ord=65021
使用splat运算符可获取数组的尾部和头部:
head, *tail = [1,2,3]
head => 1
tail => [2,3]
这也可以用另一种方式工作:
*head, tail = [1,2,3]
head => [1,2]
tail => 3
将*
方法与数组上的字符串一起使用以连接元素:
[1,2,3]*?,
=> "1,2,3"
abort
终止程序和打印字符串STDERR -短于puts
后跟exit
gets
,则可以使用~/$/
来查找其长度(如果存在,则不算结尾的换行符)[]
检查一个字符串包含另一个:'foo'['f'] #=> 'f'
tr
代替进行gsub
按字符替换:'01011'.tr('01','AB') #=> 'ABABB'
chop
代替chomp
abort
和~/$/
~/$/
gets
,其结果都存储在$_
变量中。 /regex/ ~= string
返回第一个匹配项的索引。调用~
正则表达式等效于/regex/ ~= $_
。所以就像s=gets;l= ~/$/
end
。尝试end
从您的代码中删除。
不要def...end
用来定义函数。在Ruby 1.9中使用new->运算符创建一个lambda。(->运算符是“ stabby lambda”(即“破折号火箭”)。)每个函数可节省5个字符。
# 28 characters
def c n
/(\d)\1/=~n.to_s
end
# 23 characters, saves 5
c=->n{/(\d)\1/=~n.to_s}
方法调用是c n
或c(n)
。Lambda电话是c[n]
。将每个字符更改c n
为c[n]
1个字符,因此,如果可以使用c n
5次以上,请保留该方法。
所有采用do...end
块的方法都可以采用{...}
块代替。这样可以节省3到5个字符。如果的优先级{...}
太高,请使用括号对其进行修复。
# 48 characters
(?a..?m).zip (1..5).cycle do|a|puts a.join','end
# WRONG: passes block to cycle, not zip
(?a..?m).zip (1..5).cycle{|a|puts a.join','}
# 45 characters, saves 3
(?a..?m).zip((1..5).cycle){|a|puts a.join','}
更换if...else...end
用三元运算符 ?:
。如果分支有两个或多个语句,则将它们括在括号中。
# 67 characters
if a<b
puts'statement 1'
puts'statement 2'else
puts'statement 3'end
# 62 characters, saves 5
a<b ?(puts'statement 1'
puts'statement 2'):(puts'statement 3')
您可能没有while
或until
循环,但如果有或循环,则以修饰符形式编写它们。
(a+=1
b-=1)while a<b
puts'statement 3'
必要?
如果您需要查找某个特定元素e
是否在范围内r
,则可以使用
r===e
而不是更长的时间:
r.cover?(e) # only works if `r.exclude_end?` is false
要么
r.member?(e)
要么
r.include?(e)
r===e
更短吗?
===
实现。
length
在if a.length<n
length
是6个字节,在代码高尔夫中有点昂贵。在许多情况下,您可以检查数组在给定点是否有任何东西。如果您超过最后一个索引,您将获得nil
假值。
因此,您可以更改:
if a.length<5
至 if !a[4]
-5个字节
要么
if a.length>5
至 if a[5]
-6个字节
要么
if a.length<n
至 if !a[n-1]
-3个字节
要么
if a.length>n
至 if a[n]
-6个字节
注意:仅适用于所有真实值的数组。在阵列中nil
或false
阵列中可能会引起问题。
size
…但这绝对更好。顺便说一句,也适用String
。
不要使用true
和false
关键字。
采用:
!p
为true
(谢谢,历史学家!)!0
为false
。如果您需要的只是一个伪造的值,那么您可以简单地使用p
(返回nil
)。保存一些字符。
true
(即,如果真值足够,如在if条件下),您甚至不需要!!
。
p
(计算为nil
)是较短的假值。这意味着最短的获取方法true
是!p
。
最好与新的语言功能保持同步,这将有助于您的高尔夫比赛。最新的红宝石有一些很棒的。
&.
当您调用一个可能返回的方法nil
但想要链接其他方法调用(如果没有返回)时,则会浪费字节来处理这种nil
情况:
arr = ["zero", "one", "two"]
x = arr[5].size
# => NoMethodError: undefined method `size' for nil:NilClass
x = arr[5].size rescue 0
# => 0
如果返回nil
并返回nil
整个表达式,则“安全导航运算符”将停止方法调用链:
x = arr[5]&.size || 0
# => 0
Array#dig
和 Hash#dig
深度访问嵌套元素,并使用一个简短的名字:
o = { foo: [{ bar: ["baz", "qux"] }] }
o.dig(:foo, 0, :bar, 1) # => "qux"
返回nil
是否达到死胡同:
o.dig(:foo, 99, :bar, 1) # => nil
Enumerable#grep_v
的反函数Enumerable#grep
返回与给定参数不匹配的所有元素(与相比===
)。像一样grep
,如果给出了块,则返回其结果。
(1..10).grep_v 2..5 # => [1, 6, 7, 8, 9, 10]
(1..10).grep_v(2..5){|v|v*2} # => [2, 12, 14, 16, 18, 20]
Hash#to_proc
返回一个Proc,它产生给定键的值,这可能非常方便:
h = { N: 0, E: 1, S: 2, W: 3 }
%i[N N E S E S W].map(&h)
# => [0, 0, 1, 2, 1, 2, 3]
Ruby 2.4尚未发布,但很快就会发布,并且具有一些很棒的小功能。(发布后,我将通过一些指向文档的链接来更新此帖子。)我在这篇很棒的博客文章中了解了其中的大多数内容。
Enumerable#sum
没有了arr.reduce(:+)
。您现在可以做arr.sum
。它带有一个可选的初始值参数,对于数字元素([].sum == 0
),默认值为0 。对于其他类型,您需要提供初始值。它还接受一个块,该块将在添加之前应用于每个元素:
[[1, 10], [2, 20], [3, 30]].sum {|a,b| a + b }
# => 66
Integer#digits
这将按从小到大的重要性顺序返回数字的数组:
123.digits # => [3, 2, 1]
与之相比123.to_s.chars.map(&:to_i).reverse
,这非常不错。
另外,它需要一个可选的基数参数:
a = 0x7b.digits(16) # => [11, 7]
a.map{|d|"%x"%d} # => ["b", "7"]
Comparable#clamp
它在锡上说了什么:
v = 15
v.clamp(10, 20) # => 15
v.clamp(0, 10) # => 10
v.clamp(20, 30) # => 20
由于它在Comparable中,因此您可以将其与任何包含Comparable的类一起使用,例如:
?~.clamp(?A, ?Z) # => "Z"
String#unpack1
节省了2个字节.unpack(...)[0]
:
"👻💩".unpack(?U) # => [128123]
"👻💩".unpack(?U)[0] # => 128123
"👻💩".unpack1(?U) # => 128123
Numeric#ceil
,floor
和truncate
Math::E.ceil(1) # => 2.8
Math::E.floor(1) # => 2.7
(-Math::E).truncate(1) # => -2.7
这会在Ruby的早期版本中引发错误,但在2.4中是允许的。
(a,b=1,2) ? "yes" : "no" # => "yes"
(a,b=nil) ? "yes" : "no" # => "no"
Math::E.ceil(1)
也要和。Math::E.ceil 1
floor
truncate
Enumerable#sum
,.flatten.sum
比.sum{|a,b|a+b}
(-Math::E).truncate(1)
等效于-Math::E.truncate(1)
缩短1个字节
&.
可以与这样的下标一起使用a&.[]i
(比短1个字节a&.at i
)。虽然,如果需要括号,a||a[i]
则比a&.[](i)
或短1个字节a&.at(i)
科学记数法通常可用于去除一两个字符:
x=1000
#versus
x=1e3
1e2
比100.0
需要一定百分比更好。
1.0*
比.to_f
使用||
替代or
和&&
替代and
。
除了一个字符外,and
您还可以在运算符周围保留空格(也许还有括号)。
p true and false ? 'yes' :'no' #-> true (wrong result)
p (true and false) ? 'yes' :'no' #-> 'no'
p true&&false ? 'yes' :'no' #-> 'no', saved 5 characters
p true or false ? 'yes' :'no' #-> true (wrong result)
p (true or false) ? 'yes' :'no' #-> 'yes'
p true||false ? 'yes' :'no' #-> 'yes', saved 4 characters
如果在数组上循环,则通常使用each
。但是map
也会在数组上循环,它要短一个字符。
我只是尝试了TDD代码高尔夫球挑战,即编写最短的代码以使规范通过。规格有点像
describe PigLatin do
describe '.translate' do
it 'translates "cat" to "atcay"' do
expect(PigLatin.translate('cat')).to eq('atcay')
end
# And similar examples for .translate
end
end
出于代码高尔夫球的考虑,无需创建模块或类。
代替
module PigLatin def self.translate s;'some code'end;end
一个可以做
def(PigLatin=p).translate s;'some code'end
节省13个字符!
PigLatin
,而且要@pig_latin
,$pig_latin
和'pig'['latin']
。
translate
已在上定义了nil
。
内核#p是一种有趣的方法。
使用p var
代替puts var
。这非常适合整数和浮点数,但不适用于所有类型。它在字符串周围打印引号,这可能不是您想要的。
与单个参数一起使用,p
在打印后返回参数。
与多个参数一起使用,p
以数组形式返回参数。
使用p
(不带参数)代替nil
。
p 'some string'
版画。"some string"
some string
p s
与相同puts s.inspect
,但是返回s
不要使用#each。您可以使用#map遍历所有元素。所以代替
ARGV.each{|x|puts x}
您可以用更少的字节做同样的事情。
ARGV.map{|x|puts x}
当然,在这种情况下puts $*
甚至会更短。
对于有理数和复数,有一些文字:
puts 3/11r == Rational(3,11)
puts 3.3r == Rational(66,20)
puts 1-1.i == Complex(1,-1)
=> true
true
true
您可以在字符串中使用大多数字节。 "\x01"
(6个字节)可以缩短为""
(3个字节)。如果只需要这个字节,则可以进一步缩短为?
(2个字节)。
同样,您可以将换行符缩短得像这样:
(0..10).to_a.join'
'
=> "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10"
您也可以使用?\n
和?\t
,它比"\n"
和短一个字节"\t"
。对于混淆,还存在一个空格。
即使您需要更改常量,也请使用常量而不是传递参数。口译员将警告stderr,但谁在乎。如果需要定义更多彼此相关的变量,可以像这样链接它们:
A=C+B=7+C=9
=> A=17, B=16, C=9
这比C=9;B=16;A=17
或短C=0;B=C+7;A=C+B
。
如果需要无限循环,请使用loop{...}
。长度未知的循环可能比其他循环更短:
loop{break if'
'==f(gets)}
while'
'!=f(gets);end
更多gsub / regexp技巧。使用特殊的'\1'
转义字符而不是块:
"golf=great short=awesome".gsub(/(\w+)=(\w+)/,'(\1~>\2)')
"golf=great short=awesome".gsub(/(\w+)=(\w+)/){"(#{$1}~>#{$2})")
以及特殊变量$1
等,如果您需要执行操作。请记住,它们不仅在块内定义:
"A code-golf challenge." =~ /(\w+)-(\w+)/
p [$1,$2,$`,$']
=> ["code", "golf", "A ", " challenge."]
删除空格,换行符和括号。您可以忽略很多红宝石。如有疑问,请始终尝试是否不使用它,并记住这可能会破坏一些编辑器语法突出显示...
x+=1if$*<<A==????::??==??
?\n
不错,但并不比将换行符实际放在引号内短。(与标签相同)
puts$*
更短。
x+=1;$*<<A
当一个挑战,需要你输出多行,你不必循环通过你的结果,以便打印的每一行如数组。该puts
方法将展平数组并将每个元素打印在单独的行上。
> a = %w(testing one two three)
> puts a
testing
one
two
three
将splat运算符与#p
您结合可以使它更短:
p *a
splat运算符(*@
我认为是技术上的方法)也将非数组可枚举类型转换为数组:
> p a.lazy.map{|x|x*2}
#<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>
与
> p *a.lazy.map{|x|x*2}
2
4
6
*@
不是方法,splat是语法糖
a.uniq # before
a|[] # after
^^
如果将[]
在变量中使用空数组,则可以保存更多字节:
a.uniq;b=[] # before
a|b=[] # after
^^^^^
a&a
短1字节
使用Goruby代替Ruby,后者类似于Ruby的缩写版本。您可以通过rvm安装它
rvm install goruby
Goruby允许您像编写Ruby一样编写大多数代码,但是内置了其他缩写。要找出某事物的最短缩写,可以使用helper方法shortest_abbreviation
,例如:
shortest_abbreviation :puts
#=> "pts"
Array.new.shortest_abbreviation :map
#=> "m"
String.new.shortest_abbreviation :capitalize
#=> "cp"
Array.new.shortest_abbreviation :join
#=> "j"
别名本身也可以缩写say
为也非常方便。所以代替puts
s
puts [*?a..?z].map(&:capitalize).join
你现在可以写
s [*?a..?z].m(&:cp).j
用大写字母打印字母表(这不是一个很好的例子)。此博客文章如果您有兴趣进一步阅读介绍了更多内容和一些内部工作原理。
PS:不要错过h
方法;-)
我昨天才发现这个。在第- 个位置n[i]
返回n
的位i
。例:
irb(main):001:0> n = 0b11010010
=> 210
irb(main):002:0> n[0]
=> 0
irb(main):003:0> n[1]
=> 1
irb(main):004:0> n[2]
=> 0
irb(main):005:0> n[3]
=> 0
irb(main):006:0> n[4]
=> 1
irb(main):007:0> n[5]
=> 0
n[0..3]
Array#assoc
/rassoc
如果您有一个数组数组,并且想要查找以特定值开头的子数组,请不要使用Enumerable#find
,请使用Array#assoc
:
a = [[0,"foo"],[0,"bar"],[1,"baz"],[0,"qux"]]
a.find{|x,|x==1} # => [1,"baz"]
a.assoc(1) # => [1,"baz"]
Enumerable#any?
在某些情况下,这也是很好的替代方法。
Array#rassoc
做同样的事情,但是检查子数组的最后一个元素:
a = [[123,"good"],[456,"good"]]
a.any?{|*,x|x=="bad"} # => false
a.rassoc("bad") # => nil
a.any?
行,该rassoc
怎么|x,|
办?|x|
有何不同?
x=[1,2]
vs 一样x,=[1,2]
。|x|
在上面的示例中,使用,在第一次迭代x
中将使用[0,"foo"]
。与|x,y|
,x
将0
与y
将会"foo"
。同样,with |x,|
,x
将是0
。换句话说,它说:“把第一个元素放进去,x
然后把其余的扔掉
|,y|
SyntaxError,ergo |_,y|
。但是我现在才意识到它|*,y|
可以工作,这比使用名为_
(但不能更短)的变量更干净。