您在C#中打高尔夫球有哪些一般提示?我正在寻找可以应用于编码高尔夫球问题的想法,这些想法至少在某种程度上是C#特有的(例如,“删除注释”不是答案)。请为每个答案发布一个提示。
-借鉴marcog的想法;)
您在C#中打高尔夫球有哪些一般提示?我正在寻找可以应用于编码高尔夫球问题的想法,这些想法至少在某种程度上是C#特有的(例如,“删除注释”不是答案)。请为每个答案发布一个提示。
-借鉴marcog的想法;)
Answers:
而不是将.ToString()
use +""
用于数字和其他可以安全地本地转换为字符串的类型。
.ToString() <-- 11 chars
+"" <-- 3 chars
(1+"").DoSomethingWith1String();
String.Concat(object)
使用参数调用了static ,而不是virtual调用object.ToString()
。Concat
显式转换null
为空字符串(请参阅参考资料)。没有进行“本机转换”,您可以像这样转换任何东西,只是在某些情况下结果可能不是很有用!(但空行为很可能是)。
$"{n}"
我曾经故意将程序放在其中,namespace System
以便缩短对特定类的访问。相比
using System;using M=System.Math;
至
namespace System{using M=Math;
System
名称空间中的项调用时,此功能才有用。
using System;class P...
。
using System;
在同一个名称空间中为类提供别名有关,这比我在此处显示的方式要短。
using static System.Math;
在C#6中执行此操作甚至更短(此外,您可以使用其中任何一个函数,就好像它们是真正的全局函数一样-不在类中)。最初的建议可能比using static
您需要访问多个类的建议短。
static
关键字通常比省去M.
方法调用所节省的时间要长,但是是的,它是一种选择,但是它的前期成本很高,需要大量调用才能进行摊销。
请记住,C#中最小的可编译程序为29个字符:
class P
{
static void Main()
{
}
}
因此,请从您的长度中删除该内容,然后判断所需的费用。在打印或读取输入时,C#不能与其他语言竞争,这是大多数[code-golf]
问题的核心,因此不必担心。作为C#高尔夫球手,您确实在与语言竞争。
请注意其他几点:
if
如果可能,将所有循环和语句减少到一行以删除括号。As a C# golfer, you're really competing against the language
令人难以置信的相关性
static int Main()
28个字符进行编译。
return
一些东西。
代替
bool a = true;
bool b = false;
做
var a=0<1;
var b=1<0;
如果需要多个变量,请使用此变量(由@VisualMelon建议)
bool a=0<1,b=!a;
bool a=0<1,b=!a;
在适当的情况下,将三元运算符优先于if
.. else
块。
例如:
if(i<1)
j=1;
else
j=0;
更有效:
j=i<1?1:0;
var x = input ?? "";
(我喜欢我的
i < 1
是一个复杂的语句或当名字j
很长时。海事组织,它也不能很好地传达副作用。在if (i < 1)
某种情况下,if (SendEmail(recipient))
根据副作用的成功情况返回true / false,我更喜欢if / then表示法。
j=i<1?1:0;
足够。
您可以取代 float
(这是一个别名System.Single
)与z
使用z=System.Single;
然后通过将程序放在名称空间中来替换z=System.Single;
为。(与乔伊的答案一样)z=Single;
System
这可以应用于其他值类型(使用它们的别名),结构和类
如果您需要Console.ReadLine()
在代码中多次使用(最少3次),则可以执行以下操作:
Func<string>r=Console.ReadLine;
然后就用
r()
代替
()
从第一行中删除。
auto r=Console.ReadLine;
吗?
auto
是C++
动词。var
是为C#
。无法执行此操作的原因是因为它Console.ReadLine
已重载,因此需要指定函数签名,以告知编译器需要哪个重载。
当读取命令行参数的每个字符时,而不是循环到字符串的长度时:
static void Main(string[]a){
for(int i=0;i<a[0].Length;)Console.Write(a[0][i++]);
}
您可以使用try / catch块查找结尾来保存字符:
static void Main(string[]a){
try{for(int i=0;;)Console.Write(a[0][i++]);}catch{}
}
这适用于数组中的任何数组,例如:
string[]
int[][]
IList<IList<T>>
在C#6中,可以使用lambda定义函数:
int s(int a,int b)=>a+b;
这比定义这样的函数要短:
int s(int a,int b){return a+b;}
而不是使用:
Enumerable.Range(0,y).Select(i=>f(i))
获得可枚举与函数的结果f
对每个int
在[0,y]
你可以使用
new int[y].Select((_,i)=>f(i))
如果您需要程序string
中实现的任何东西,Enumerable
也可以使用它们
var s="I need this anyway";
s.Select((_,i)=>f(i))
如果您需要Dictionary<TKey, TValue>
在代码中至少使用两次泛型,则可以声明一个字典类,如下例所示:
class D:Dictionary<int,string>{}
然后就用
D d=new D{{1,"something"},{2,"something else"}};
而不是Dictionary<int,string>
为每个实例重复。
我已经在这个答案中使用了这种技术
using D = System.Collections.Generic.Dictionary<int,string>;
您可以使用float
和double
文字来节省一些字节。
var x=2.0;
var y=2d; // saves 1 byte
当你需要一些int
算术返回一个float
或者double
你可以用文字来强制转换。
((float)a+b)/2; // this is no good
(a+b)/2.0; // better
(a+b)/2f; // best
如果遇到必须强制转换的情况,则可以使用乘法来节省一些字节。
((double)x-y)/(x*y);
(x*1d-y)/(x*y); // saves 5 bytes
(x-y)*1d/x/y;
记住私人或公共存在于何处,例如:
class Default{static void Main()
相比于
public class Default { public static void Main()
Main
还暗含了另一个好处:例如,与Java相比,不需要任何参数。
对于单行lambda表达式,可以跳过方括号和分号。对于单参数表达式,可以跳过括号。
代替
SomeCall((x)=>{DoSomething();});
采用
SomeCall(x=>DoSomething);
SomeCall(DoSomething)
甚至更好
循环播放:
变量声明:
int max;
for(int i=1;i<max;i++){
}
成为:
int max,i=1;
for(;i<max;i++){
}
而且,如果您只需要或仅使用i变量一次,则可以从-1(或0,具体取决于循环情况)开始并内联递增:
int max,i=1;
for(;i<max;i++){
Console.WriteLine(i);
}
至
int max,i=1;
for(;i<max;){
Console.WriteLine(++i);
}
而且这减少了一个字符,并且也使代码有些混乱。只需对FIRST i
参考执行此操作,例如:(授予的一个字符优化并不多,但可以提供帮助)
int max,i=1;
for(;i<max;i++){
Console.WriteLine(i + " " + i);
}
至
int max,i=1;
for(;i<max;){
Console.WriteLine(++i + " " + i);
}
当循环不必增加时i
(逆序循环):
for(int i=MAX;--i>0;){
Console.WriteLine(i);
}
++
在这种情况下,我通常将它们直接放入循环头中:for(;++i<max;)
这既易于遵循,又更容易出错。
for
头文件中放置另一个(较早的)语句,然后再保存一个字符。
for(;i<max;)
为while(i<max)
。字节数相同,但对我来说看起来更干净。
在某些情况下,输出参数可以保存字符。这里有一个稍微做作的例子,一个10针的保龄球的成绩算法。
带有return语句:
........10........20........30........40........50........60........70........80........90.......100.......110.......120.......130.......140.......150..
public double c(int[]b){int n,v,i=0,X=10;double t=0;while(i<19){n=b[i]+b[i+1];v=b[i+2];t+=(n<X)?n:X+v;if(b[i]>9)t+=b[i+(i>16|v!=X?3:4)];i+=2;}return t;}
并带有输出参数:
........10........20........30........40........50........60........70........80........90.......100.......110.......120.......130.......140.......
public void d(int[]b,out double t){int n,v,i=0,X=10;t=0;while(i<19){n=b[i]+b[i+1];v=b[i+2];t+=(n<X)?n:X+v;if(b[i]>9)t+=b[i+(i>16|v!=X?3:4)];i+=2;}}
此处的输出参数总共保存5个字符。
一个真正简单的节省空间的改进是插值。代替:
string.Format("The value is ({0})", (method >> 4) + 8)
仅用于$
内联表达式:
$"The value is ({(method >> 4) + 8})"
这与C#6.0中的新表达式主体一起,应该可以使任何简单的字符串计算挑战在C#中变得非常容易。
i+$" bottles of beer";
它比短$"{i} bottles of beer"
。
$
。
{i}
前面有两个,中间是一个;)
使用C#lambda。由于PPCG允许使用lambda进行输入/输出,因此我们应该使用它们。
经典的C#方法如下所示:
bool Has(string s, char c)
{
return s.Contains(c);
}
作为lambda,我们将写
Func<string, char, bool> Has = (s, c) => s.Contains(c);
也允许匿名lambda:
(s, c) => s.Contains(c)
消除所有噪音并集中注意力!
更新:
我们可以提高一步多用讨好的@TheLethalCoder评论:
s => c => s.Contains(c);
@Felix Palmen生成的示例:如何计算WPA密钥?
当您只有两个参数时,这将很有帮助,然后使用一个空的未使用变量_
会更好。有关此内容,请参见meta post。我在这里使用这个技巧。您将不得不更改一些功能。示例:在线尝试!
s=>c=>...
s=>s.Contains
。
(string s,char c)=>s.Contains(c)
的Compute
实例方法System.Data.DataTable
允许评估一个简单的字符串表达式,例如:
namespace System.Data
{
class P
{
static void Main()
{
Console.Write(new DataTable().Compute("30*2+50*5/4",""));
}
}
}
本身不是很“高尔夫”,但有时可能有用。
通常,要交换两个变量,必须声明一个临时变量来存储值。看起来像这样:
var c=a;a=b;b=c;
那是16个字节!还有其他一些更好的交换方法。
//Using tuples
(a,b)=(b,a);
//Bitwise xoring
a=a^b^(b=a);
//Addition and subtraction
a=a+b-(b=a);
//Multiplication and division
a=a*b/(b=a);
后三个仅适用于数值,并且如仅ASCII指出的那样,后两个可能会导致ArithmeticOverflow异常。以上所有都是12个字节,与第一个示例相比节省了4个字节。
使用LinqPad将使您有可能消除所有程序开销,因为您可以直接执行语句。(并且在codegolf中应该是完全合法的。没有人说您需要一个.exe)
使用.Dump()
扩展方法完成输出。
.Dump()
;)
(了解您的运算符优先级的特殊情况!)
使用%
用于紧密结合(有点)有限减法。这可以为您在减法周围节省一对括号,您想要将其乘以或除以某物。但请注意,它有严重的局限性。
代替
char b='5'; // b is some ASCII input
int a=(b-48)*c; // we want to find the numerical value of b, and multiply it by something ('0'==48)
考虑
char b='5'; // b is some ASCII input
int a=b%48*c; // only good for ASCII within 48 of '0' (positive only)!
例子:
'5'%'0'*2 -> 10
'5'%'0'*-1 -> -5
'5'%'0'/2 -> 2
我只是发现了这一点,所以我觉得以后在使用ASCII时记住它会很有价值。(我目前正在打高尔夫球,在那儿我使用ASCII表示紧凑的数字表示形式,但是需要乘以1
或-1
基于另一种条件,并且该条带化2字节)
今晚在“沟渠中”发现的同时改进了一些高尔夫球代码...如果您有要处理的类,则可以在构造函数中进行工作以保存声明方法。
我在减少控制台应用程序时发现了这一点-因为有一个static void Main()
,所有函数和变量都必须声明为静态。我创建了一个包含成员函数和变量的嵌套类,其主要工作在构造函数中执行。这还将字符保存在调用代码中。
例如带有方法的类:
class a
{
public void b()
{
new c().d("input");
}
}
class c
{
public void d(string e)
{
System.Console.Write(e.Replace("in", "out"));
}
}
类在构造函数中的工作方式:
class a
{
public void b()
{
new c("input");
}
}
class c
{
public c(string e)
{
System.Console.Write(e.Replace("in", "out"));
}
}
本示例保存9个字符。
使用Action
like Func
可以将函数设置为变量。Action
不返回任何内容(void
),因此非常适合打印。
例如:
Action<string>w=Console.WriteLine;
w("Hello World");
本技巧的灵感来自@ W0lf 与with 结合使用的出色示例Func
ReadLine
。
如果需要声明多个空/匹配字符串,则可以使用以下命令节省一些字节:
string a="";string b="";string c=""; // 36 bytes
var a="";var b="";var c=""; // 27 bytes
string a="",b="",c=""; // 22 bytes
string a="",b=a,c=a; // 20 bytes
不幸的var a="",b=a,c=a;
是是非法的,因为implicitly type variable cannot have multiple declarators
var a=b=c=""
喜欢用javascript吗?