<所有语言>打高尔夫球的技巧


81

这篇文章的目的是收集所有可以轻松应用的高尔夫球技巧,<all languages>而不是特定的技巧。

仅发布其逻辑可应用于大多数语言的答案

请给每个答案一个提示


5
“多数”采用什么度量标准?
停止转动逆时针

2
@leftaroundabout由同一个词的指标
ajax333221

8
问题在于,许多语言都是(通常是短暂的)实验性语言,具有非常不典型的范例,对于它们而言,典型的编程表达式根本没有任何意义。因此,“多数所有语言”几乎不可能实现。您应该以某种方式将其限制,例如“ codegolf.SE上经常使用的多种语言”。目前,答案看起来很像“大多数远程C衍生语言”,但是,尽管所有书面代码中的绝大多数都是用它们编写的,但并不是大多数语言
停止转动逆时针

3
leftroundabout,我想我们都知道它们的大致意思。这主要涉及与语言无关的优化,即不仅在Brainfuck中有用,而且在Python,C,Java和Fortran中同时有用。您可以在许多类似的语言中应用的一般思路。我认为技巧和CW问题不需要如此精确和具体。这是关于帮助他人打高尔夫球,而不是惹恼他们。
乔伊

14
希望没有人会创建一个名为语言<all languages>...
mbomb007

Answers:


72

合并循环

通常,您可以将两个后续循环或两个嵌套循环合并为一个。

之前:

for (i=0; i<a; i++) foo();
for (i=0; i<b; i++) bar();

后:

for (i=0; i<a+b; i++) i<a?foo():bar();

ugoren的循环仍然不一样。@加菲是正确的。
kaoD

5
在两种情况下,@ kaoD都foo称为a时间,bar称为b时间。这是因为在“之后”中,循环运行a+b时间,即第一个a调用foo,下一个调用bar
ugoren

我又在看这个(很久以后),我现在不明白我自己的问题。我也许以前不了解三元运算?我现在的看法很有意义。
加菲

1
糟糕,我很晚才读到。你是对的!
kaoD

3
很相似:for(y=0;y<Y;++y)for(x=0;x<X;++x)能经常成为for(i=0;i<X*Y;++i)x取代i%Xy被取代i/X
林恩

62

仅提及显而易见的一点:

对您选择的算法提出疑问,然后尝试全新的方法。

打高尔夫球时(尤其是较难的问题导致更长的程序),您可能会经常选择最初选择的路线而无需尝试其他基本选择。当然,您可能一次只打一条或几条线,也可能只是整体思路的一部分,但通常不尝试完全不同的解决方案。

这在Hitting 495(Kaprekar)中尤其明显,在许多语言中,它偏离实际算法并寻找可用于获得相同结果的模式,这在许多语言中都比较短(只是J语言)。

不利的一面是您可能会多次解决同一件事。但是它几乎可以在除HQ9 +之外的所有语言中使用(在该语言中,找到另一种输出Hello World的方法会有些徒劳)。


12
+1除了对打高尔夫球有益之外,对于许多现实世界中的任何程序员而言,这都是不错的练习!
加菲2012年

52

使用测试驱动的开发

如果代码必须处理各种输入,则编写全面的测试,并轻松快速地运行它们。这样一来,您就可以一次尝试一次冒险转换一次。打高尔夫球就变得像有错误意图的重构。


4
我使用这种方法的衍生产品。由于问题本身通常很简单,因此我编写了一个可以完成此任务的程序。通常,这是“可读的”,因此简洁,但有换行符等。我将此文件复制到一个新位置,然后打高尔夫球,不时检查程序是否为某些选定的输入返回相同的值。如果我犯了一个错误的程序,遗留了一个损坏的程序,没有对所做更改的记忆,也没有对高尔夫球的理解,那么我就有一些“规格”被保存为参考资料。
shiona 2013年

2
我喜欢这种方法,这就是我倾向于针对我编写的所有问题包括全面的测试套件的原因之一。
2015年

@RubberDuck 经常严格遵守“ 不要重复自己”的原则。
乔纳森·弗雷希

48

尝试减少逻辑陈述

例如,如果AB是布尔值,并且您的语言在某种程度上将布尔值像数字一样对待,A and (not B)并且A>B是等效的。例如在Python中

if A and not B:
    foo()

是相同的:

if A>B:
    foo()

3
我从来没有想过。
cjfaure 2014年

27
B>A or foo()这将是表达这种情况的更短的方法,利用对布尔表达式的惰性求值以确保仅在需要时才计算事物。
scragar 2014年

5
@scragar:正确,但这不是本文的重点。(尽管这是一个有价值的独立技巧。)
Wrzlprmft 2014年

3
@scragar,B>A or foo将评估foo是否B==A不是我们想要的。(对吗?)
msh210 '16

2
另外,如果您有较长的约束条件(例如使用5/6参数),则可以使用Truth表和
Karnaugh

33

使用您已有的值初始化变量。

而不是x=1尝试查找已经等于1
的值。例如,函数的返回值:printf("..");x=0;-> x=!printf("..");。最简单的是0,因为您总是可以取反,或者当您只需要正确的真值时(不必关心它是1还是19)。


4
在C中,您可以将main中的argc用作1。请参阅:codegolf.stackexchange.com/questions/1034/reinvent-the-for-loop/…– std''OrgnlDave 2012
19:39

1
@ std''OrgnlDave,是的,但是这个问题是所有语言都通用的。
ugoren

33

一元~用于x+1x-1

此技巧适用于具有一元按位求反运算符~和一元正则求反运算符的语言-

如果您的程序偶然包含表达式-x-1,则可以将其替换~x为保存字节。这种情况不会经常发生,但是请注意,如果我们-对两个表达式求反()x+1等于,将会发生什么-~x。同样,x-1等于~-x。(想到波浪号的指向是:右边是+,左边是-。)

这很有用,因为在我能想到的所有语言中,都有这些运算符,它们的优先级高于大多数运算符。这样可以节省括号。在这里观看我们如何保存四个字节:

(x+1)*(y-1)     ==>    -~x*~-y

30

压缩空格

了解您所用语言中空格的规则。某些标点符号或其他字符可能不需要任何周围的空格。考虑以下Bourne shell函数:

f () { echo a; echo b; }

在Bourne shell中,();是元字符,不需要周围的空格。但是,{}是单词,需要空格,除非它们在元字符旁边。我们可以打高尔夫球旁边的4个空间();,但是必须保持在{和之间的空间echo

f(){ echo a;echo b;}

Common LispPicoLisp中()是元字符。考虑以下代码以查找两个数字的平均值:

(/ (+ a b) 2)

我们可以打2个球。

(/(+ a b)2)

有些语言对空格有奇怪而微妙的规则。考虑一下这个Ruby程序,该程序输出整数行的和和乘积。

#!ruby -an
i=$F.map &:to_i
puts"#{i.reduce &:+} #{i.reduce &:*}"

每个人&在自己之前都需要一个空间。在Ruby中,i=$F.map &:to_i表示i=$F.map(&:to_i)在何处&传递block参数。但是,i=$F.map&:to_i表示二进制运算符i=$F.map.&(:to_i)在哪里&

这种怪异现象发生在使用歧义标点的语言(例如Perl或Ruby)中。如有疑问,请使用REPL或编写简短的程序来测试空白规则。


1
为什么在“ {”和“ echo”之间需要一个空格,而在“;”之间却不需要 和“回声”?
瑞安

3
我使用了OpenBSD sh(1)手册中的术语,其中说“ {”是保留字,而“;” 是一个元字符。因此,“ {echo”是一个单词,而“; echo”是两个单词。其他手册可能对此有所不同。另外,Z shell zsh具有不同的规则。
kernigh 2014年

28

如果多次使用,请为函数分配新名称

x = SomeLongFunctionName
x(somedata)
x(somemoredata)
etc

仅当我们使用足够的调用时x
elipszilon

28

单字母变量名

您有52个;全部使用!不要害怕尝试不同的方法并比较长度。了解语言以及可用的特定快捷方式/库功能。


8
非区分大小写的语言为26。:-)
加菲2012年

12
通常$_可用作标识符。
格里芬2012年

4
@Gaffi:对于允许Unicode标识符的语言来说,这已经足够了,除非该任务将您限制为ASCII或计算字节而不是字符。
hammar 2012年

如果您是在计算字节数而不是unicode,那么使用扩展的ascii可能是一种挤压其他
〜120

2
@是T-SQL中的有效变量名,请使用它代替@a
BradC

25

使用条件运算符。

条件运算符

bool ? condition_true : condition_false

就字符而言,比IF 语句更有益。

if(a>b){r=a;}else{r=b;}

可以写成

r=a>b?a:b;

25
没有三元语言的语言可以a&&b||c代替使用。稍长,但仍比短if
Michael Kohl 2012年

再说一次,有些人不能使用任何一个选项(想到VBA),但两者都是很好的建议。:-)
加菲2012年

1
Gaffi:VBA具有Iff,尽管它是一个功能,所以需要评估所有参数。
2012年

if语句中使用三进制也非常有帮助if(a ? b : c)
Jojodmo 2015年

4
@MichaelKohl注意,a&&b||c可以返回c的时候a是真的当且仅当b是假的,稍胜一筹的情况下,但是我们不应该忘记,^^
Katenkyo

24

编写代码说明

编写说明会迫使您再次彻底查看代码的每个部分,并在明确编写某些段落时表达您的想法和选择。这样做时,您可能会发现可以使用不同的方法来节省一些字节,或者您下意识地做出了不一定成立的假设。

这个技巧类似于询问您选择的算法并尝试全新的东西 ; 但是,我发现,实际写下每个部分的工作方式有时对于了解替代品至关重要。

另外,包括解释在内的答案对于其他用户而言也更有趣,因此更有可能被接受。


23

仔细检查您的字符数

听起来很容易,但是通过小心一点,您可能根本不执行任何操作来“保存”一些字符!

如果您使用的是Windows,则可能会输入\r\n而不是仅输入内容,\r或者\n当您按Return键时-每行增加一个额外的字节!转动控制字符只是为了再次检查您是否没有这样做。

在Notepad ++中\r\n,只需\r转到即可将所有行尾转换为Edit > EOL Conversion > UNIX/OSX Format

另外请确保您的字符数中不包含任何结尾的空格!代码最底行的换行符也无关紧要,因此也无需计数。


我认为我从来没有见过这样的案例……
Jacob

4
我自己刚刚遇到了这个问题(因此为什么要添加它)。
肖恩·拉瑟姆

21

仔细阅读问题

打高尔夫球的代码与理解问题(即使在任何其他情况下会暗示什么是问,什么不是问题)一样,与产生(可能)满足要求的代码一样重要。

除了明确要求的输入外,无需处理任何其他输入。如果存在一些测试用例,并且没有一般性要求,则您的代码仅在这些情况下可用。等等。


15
我认为这里最好的标题是“不处理不需要的边缘情况”。“尝试查找漏洞”一词使我想到了避免通过巧妙地重新解释规则来进行指定操作的方法,而您所提供的仅仅是避免过度实施解决方案的好建议。
Jonathan Van Matre 2014年

1
是的,但是巧妙地重新定义规则也是代码打高尔夫的一部分!(0个字符解决方案,等等)
Tobia 2014年

8
不过,那将/应该是不同的答案。例如,由于OP不需要浮点支持而实施仅适用于int的解决方案,而由于“您不必说必须成为实际素数”。
Jonathan Van Matre 2014年

我认为某些OP包含“测试用例可能会更改;您的代码在更改后仍必须工作”的通知,并且如果他们只看到一个对测试用例进行硬编码的答案,则可以对其进行真正的更改。
暴民埃里克

20

使用按位运算检查0到2 n -1 之间的数字

可能会有些优势,但有时可能会派上用场。它依赖于以下事实:m = 2 n -1应用于的所有数字的最右边n位设置为1。

所以,7 10 == 00000111 2,15 10 == 00001111 2,31 10 == 00011111 2等。

诀窍是x&~m。每当这将返回true x不是介于0 m(含),否则为false。它从下一个最短的等价表达式保存6个字节x>=0&&x<=m,但显然仅在m满足2 n -1时有效。


18

重用函数参数而不是新变量


1
举例来说,在C语言中,您的主函数始终会传递给程序的参数数量(为1-程序名-默认为“默认”),因此对于main(i){...您而言,现在有了一个值为1的变量,而不必做任何作业。2个字符保存有..
格里芬

6
我认为它非常特定于C。脚本语言不需要声明,并且在大多数编译语言中,定义变量的时间并不比定义参数的时间长。
ugoren

在Java中,当在函数中需要与一个参数具有相同类型的数组时,可以通过将该参数放在最后并使其成为vararg参数来节省一些字节;(用于在函数中
删除

18

大于/小于保存数字:

//use:
if(n>9){A}else{B}
//instead of:
if(n<10){B}else{A}

只要记住将代码从交换ifelse,它们将做完全相同的事情(或切换不等式的一面)!

注意:这可以应用10的任何幂及其负数:...-100, -10, 10, 100...

(源链接)


我不确定我是否明白这一点。这减少了什么?
加菲2012年

@Gaffi,您保存一个字符,它们的作用完全相同
ajax333221 2012年

与什么选择?抱歉,我没有固执己见,只是不明白。(newb,这里,显然是...)
加菲2012年

1
知道了 适用于从9到10、99到100等的整数转换。抱歉,我花了这么长时间!(我只说整数,因为我可以看到n = 9.5的问题...)
Gaffi 2012年

8
同样在某些语言中(如果支持),如果您的数字足够大/小,则科学计数法可能实际上为您节省了一些字符:if(n>99999)vsif(n<1e5)
scragar

16

使用>和<代替> =和<=

当对硬编码的整数值检查,使用><替代>=<=在可能的情况。例如,使用

if(x>24&&x<51)

比使用短2个字节

if(x>=25&&x<=50)

3
相关新闻:如果您确定的结果不能为负数,您可以使用<1,而不是==0作为零检查(或>0代替!=0用于镜像检查)。
凯文·克鲁伊森

1
您不应该添加有关x整数的注释吗?
扎卡里

15

避免过早的循环中断

如果通过循环运行以检查一个或多个布尔检查实例,则可能会使更高效的程序在第一个true值上退出循环。但是,删除中断和循环遍历所有迭代可以缩短代码。

int main() {
bool m = false;
int n = 1000;
for (int i = 0; i < n; i++) {
if (i >= 100) {
m = true;
break; // remove this line
}
} 
return 0;
}

5
if在以下情况下,您还可以简化语句:m|=i>=100。(在这种情况下,您也可以简化i>=100i>99,但是在这里不是很重要)
marinus

15

-代替!=

用于数字比较:

如果a等于b,则a-b得出0,这是虚假的。0真理以外的任何东西;因此,
如果在布尔上下文中使用,a-b<=>a!=b

如果将其与if/else或与三元运算符一起使用,这还可以为您节省一个字节以确保相等:
a==b?c:d<=>a-b?d:c


12

拆分字符串以获得长数组

大多数语言都有一种方法可以将某种形式的令牌周围的字符串拆分为字符串数组。一旦长度达到与语言相关的阈值,这将不可避免地比数组文字短,因为每个字符串的额外开销将是一个1字符令牌的一个副本,而不是(至少)两个字符串定界符。

例如,在GolfScript中

["Foo""Bar""Baz""Quux"]  # 23 chars

变成

"Foo
Bar
Baz
Quux"n/  # 20 chars

对于某些语言,阈值低至一个字符串。例如,在Java中,

new String[]{"Foo"}  // 19 chars

变成

"Foo".split("~")  // 16 chars

6
值得注意的例外是Ruby,它提供了一个字符串数组文字,该文字以两个字节为代价自动在空格上分割:%w{Foo Bar Baz Quux}
Martin Ender 2014年

1
Perl提供了类似的东西:qw(Foo Bar Baz Quux)成为字符串列表。
BenGoldberg '16

12

了解其他人做了什么

除了很有趣之外,如果您检查其他人的代码,有时还可以发现一个您没有想到的好算法,或者一个您忽略的技巧(有时是很明显的技巧)。

有时候,您可以将现有的答案翻译成另一种语言,并从另一种语言的优点中受益。


10

知道您的运算符优先级

每当您组合多个表达式时,请检查您的语言的运算符优先级表,以查看是否可以对内容进行重新排序以保存括号。

例子:

  • 在我所知道的所有语言,位运算符比布尔运算符的优先级高: (a&b)&&c不需要括号:a&b&&c就像(a*b)+c没有。
  • a+(b<<c)可以重写为a+b*2**c
    在此示例中,这不会保存任何内容,但是如果c是小的整数文字(<14),它将保存任何内容。
  • 位运算比大多数算术运算优先级较低,所以如果你的语言含蓄地蒙上布尔为int,你可以保存一个字节a<b&&c<da<b&c<d(除非你需要短路评价)

7

较短的循环

如果您有X报表{里面}的for循环,您可以将X-1报表()的第二个分号后的for循环for(blah;blah;HERE),以节省3个字节。(使用逗号分隔语句,

代替

for(int i=0;i<9;){s+=s.length();println(i++);}

您可以将其中一个语句移到for循环的(大括号中,)而将另一个移出

for(int i=0;i<9;println(i++))s+=s.length();

并保存3个字节(由于@ETHProductions而又节省了1个字节)


简单地说,

代替

for(blah;blah;){blah 1;blah 2;...;blah X}

移动语句,以便最终得到这个

for(blah;blah;blah 2,...,blah X)blah 1;

并保存3个字节


@ETHproductions感谢您打高尔夫球:)
Kritixi Lithos

而如果for是最后陈述时,;变成可选
elipszilon

7

一元~用于a-b-1a+b+1

除了@Lynn关于x+1→ 的建议之外-~x;和x-1~-x,您也可以打高尔夫球a-b-1a+b+1

a-b-1    // 5 bytes
a+~b     // 4 bytes

a+b+1    // 5 bytes
a-~b     // 4 bytes

似乎您不会经常使用的技巧,有点像使用~x-x-1不是经常发生的技巧,但是我已经使用了足够的时间,在这里将其视为有用的技巧。特别是在使用数组索引的情况下,您可能会在某些情况下使用以上这些。


6

压缩或/和条纹

当试图挤压由ands(或ors,在这种情况下,只用“ any”代替“ all”)链接的条件时,我想到了一个简单的技巧。

例如:

if a>0 and a<10 and a+b==4 and a+3<1:

成为

if all([a>0,a<10,a+b==4,a+3<1]):

那是很酷的,我必须尝试一下!
stokastic

4
哪些语言具有all(array-of-Booleans)内置功能?
彼得·泰勒

3
Ruby拥有了。[a>0,a<10,a+b==4,a+3<1].all?
kernigh 2014年

4
尽管如果这是Python,您可能会使用if 10>a>0 and a+b==4>1>a+3:
Sp3000(2014年

@PeterTaylor Haskell也有
骄傲的haskeller 2014年

6

依靠编译器提供所需的性能。

确保知道编译器可以保证哪些优化以及在哪些优化级别可以自由使用它们。即使业绩并不关心要求,您仍然可以在最佳化测试,然后只贴一个字符,因为你的代码仍然是技术上没有编译器标志有效。

考虑以下Haskell函数来计算2 ^ n(忽略Haskell已经具有内置的幂运算符或三个幂)(23个字符):

p 0=1;p x=p(x-1)+p(x-1)

问题是-速度太慢了,它以指数速度运行。这可能会使您的代码不可测试,或者无法解决问题给出的任何性能限制。您可能会想使用临时变量或立即调用的函数文字以避免重复的函数调用(25个字符):

p 0=1;p x=(\y->y+y)$p$x-1

但是编译器已经可以为您做到这一点,您只需要将其设置-O为编译器标志即可!不必告诉每个站点几个额外的字符来手动消除常见的子表达式,只需告诉编译器为您做基本优化,整个程序中总共可以包含一个或两个字符。


@ETHproductions是的,对不起,我做了
John Dvorak

第一个例子不应该是p(x-1)*2吗?
Cyoce '17

5

也许有些明显,但是...

利用运算符的返回值

请记住,赋值运算符返回一个值!

例如,如果要向x添加y,然后检查x是否大于某个值,则可以执行

if(25<x+=y)

代替

x+=y;if(x>25)

或者,也许您想在修剪后找到字符串的长度:

strlen(s=trim(s))

而不是

s=trim(s);strlen(s)

您可以通话中使用哪种语言进行分配?还是那个关键字arg?

2
我认为赋值至少是C,C ++,C#和Java中的表达式(具有分配的变量的新值作为它们的表达式值)。a = (b=c)+1;设置bc,然后设置ab+1
林恩(Lynn)2015年

@Lynn试试a=1+b=c。您可以将PHP和JavaScript添加到列表中。
Titus

2
Ruby做到最好。它给=运算符的优先级在左边比在右边更高,因此1+x=2有效,并且计算结果为3
Cyoce

@Cyoce afaik在所有语言中,分配都是一种表达方式。
泰特斯

5

利用语言版本/编译器/环境怪癖/新功能

这对于尤其有用,但可以应用于其他挑战。有时,编译器错误可能使字节减少,实现错误可能使您节省一些字符,或者真正的前沿功能可以提高得分。


4

如果可能,使用And / Or合并多个/嵌套。

即:

if (a && (b || c)) {

}

代替:

if (a) {
    if (b) {
        //Do Stuff
    } elseif (c) {
        //Do same stuff
    }
}

5
同样,使用位条件(&,`|)删除更多字符。
FUZxxl 2012年

2
尽管在某些情况下使用按位&代替而不是&&删除1个字符会弄乱运算符的优先级,并且您必须加上括号才能使其正常工作。
DollarAkshay

4

寻找更好的方法来初始化变量

其他一些答案几乎已经提到了这一点,但是在许多(严格键入?)语言中,初始化x为空字符串的时间较短,例如:

x:=""

x作为空符文(char),例如:

x:=''

var x string

var x rune

使用预先存在的值显然是首选,但并非那么容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.