C#中的代码高尔夫球技巧


62

您在C#中打高尔夫球有哪些一般提示?我正在寻找可以应用于编码高尔夫球问题的想法,这些想法至少在某种程度上是C#特有的(例如,“删除注释”不是答案)。请为每个答案发布一个提示。

-借鉴marcog的想法;)


最佳提示=>如果您不想为挑战提交最长的答案,请在.NET旁使用其他内容。.NET的设计非常冗长,可让IDE进行键入。实际上,只要您拥有IDE拐杖,这对于一般编程来说并没有听起来那么糟糕,但是对于代码争夺而言,这种策略肯定会失败。
krowe

原谅我的日历照片,这是我很快就能找到的。
地下

Answers:


59

而不是将.ToString()use +""用于数字和其他可以安全地本地转换为字符串的类型。

.ToString() <-- 11 chars
+""         <--  3 chars

5
这也适用于JS。
Cyoce '16

1
如果您以后需要使用字符串来包含花括号,则通常通常为5个字符(1+"").DoSomethingWith1String();
。– TheLethalCoder

1
如果您需要字符串,通常会存储它。几乎所有其他用法都可以本地推断ToString()...
jcolebrand

1
请注意,这实际上String.Concat(object)使用参数调用了static ,而不是virtual调用object.ToString()Concat显式转换null为空字符串(请参阅参考资料)。没有进行“本机转换”,您可以像这样转换任何东西,只是在某些情况下结果可能不是很有用!(但空行为很可能是)。
VisualMelon

1
替代方法- 字符串插值$"{n}"
Andriy Tolstoy

41

我曾经故意将程序放在其中,namespace System以便缩短对特定类的访问。相比

using System;using M=System.Math;

namespace System{using M=Math;

9
只需记住,一次使用即可解决问题,因此最好完全限定类/功能。仅当您必须多次调用某项,并且甚至仅对System名称空间中的项调用时,此功能才有用。
尼克·拉尔森

您也可以这样做using System;class P...
拉丹2015年

@Logan:这不仅仅与using System;在同一个名称空间中为类提供别名有关,这比我在此处显示的方式要短。
2015年

using static System.Math;在C#6中执行此操作甚至更短(此外,您可以使用其中任何一个函数,就好像它们是真正的全局函数一样-不在类中)。最初的建议可能比using static您需要访问多个类的建议短。
牛奶

@milk:附加static关键字通常比省去M.方法调用所节省的时间要长,但是是的,它是一种选择,但是它的前期成本很高,需要大量调用才能进行摊销。
乔伊,

30

使用var的声明和初始化(单)的变量,以节省类型的字符:

string x="abc";

变成

var x="abc";

int当然不是特别必要的。


2
请记住,var例如不能有多个声明var x="x",y="y";符。
伊恩H.17年


23

请记住,C#中最小的可编译程序为29个字符:

class P
{
    static void Main()
    {   
    }
}

因此,请从您的长度中删除该内容,然后判断所需的费用。在打印或读取输入时,C#不能与其他语言竞争,这是大多数[code-golf]问题的核心,因此不必担心。作为C#高尔夫球手,您确实在与语言竞争。

请注意其他几点:

  • if如果可能,将所有循环和语句减少到一行以删除括号。
  • 如果在stdin和命令行之间提供了选项,请始终使用命令行!

这通常也涉及三元;)
jcolebrand 2011年

1
As a C# golfer, you're really competing against the language 令人难以置信的相关性
dorukayhan

1
实际上,这是不正确的。它也使用static int Main()28个字符进行编译。
Metoniem '17


21

代替

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;
VisualMelon

18

在适当的情况下,将三元运算符优先于if.. else块。

例如:

if(i<1)
    j=1;
else
    j=0;

更有效:

j=i<1?1:0;

15
我是唯一一个觉得第二种情况本质上对这样的事情更具可读性的人吗?我经常这样做。另外,如果我需要避免为空条件(例如在字符串上),我可以做类似的事情var x = input ?? "";(我喜欢我的
凝聚力

有时候,它远不是一个更具可读性的选项,尤其是当它i < 1是一个复杂的语句或当名字j很长时。海事组织,它也不能很好地传达副作用。在if (i < 1)某种情况下,if (SendEmail(recipient))根据副作用的成功情况返回true / false,我更喜欢if / then表示法。
尼克·拉尔森

11
在第二种情况下不需要括号- j=i<1?1:0;足够。
DankoDurbić2011年

3
该问题要求提供一些特定于C#的技巧。这是所有语言提示中包含的一种
彼得·泰勒

4
@PeterTaylor我在3年前就回答了这个问题,就在您创建链接的线程之前
Nellius 2014年

15

有效利用

您可以取代 float(这是一个别名System.Single)与z使用z=System.Single;

然后通过将程序放在名称空间中来替换z=System.Single;为。(与乔伊的答案一样)z=Single;System

这可以应用于其他值类型(使用它们的别名),结构和类


14

如果您需要Console.ReadLine()在代码中多次使用(最少3次),则可以执行以下操作:

Func<string>r=Console.ReadLine;

然后就用

r()

代替


我认为您需要()从第一行中删除。
mellamokb '04

@mellamokb是的,谢谢!固定。
克里斯蒂安·卢帕斯库

1
你不能auto r=Console.ReadLine;吗?
Claudiu 2014年

2
@claudiu不,很遗憾,不是ideone.com/jFsVPX
Cristian Lupascu 2014年

@Claudiu autoC++动词。var是为C#。无法执行此操作的原因是因为它Console.ReadLine已重载,因此需要指定函数签名,以告知编译器需要哪个重载。
GreatAndPowerfulOz

14

当读取命令行参数的每个字符时,而不是循环到字符串的长度时:

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>>

7
那真是令人恐惧...我喜欢它!
Alex Reinking

天哪

这真是邪恶!
GreatAndPowerfulOz

13

使用Lambda定义C#6中的函数

在C#6中,可以使用lambda定义函数:

int s(int a,int b)=>a+b;

这比定义这样的函数要短:

int s(int a,int b){return a+b;}

3
C#6提供了全新的代码高尔夫球功能
jcolebrand 2015年

在C#7中,可以在另一个函数内部创建本地函数。我怀疑这在打高尔夫球时是否会有所帮助,但是这仍然只是个整洁的窍门。
TehPers '17

1
那不是正式的lambda。这是一个身体强壮的成员
递归

13

LINQ

而不是使用:

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))

我在回答沙米尔(Shamir)的秘密共享”挑战时使用了这个技巧。
aloisdg's

我不认为,如果不对优化启用的枚举进行迭代,则字符串部分不会执行。直到我做了.ToArray();,我才失败了。除此之外,惊人的技巧!
加斯帕79年

是的,可枚举是惰性的,但是对于所有三个示例都是正确的,而不仅仅是带有字符串的示例。
raggy

11

如果您需要Dictionary<TKey, TValue>在代码中至少使用两次泛型,则可以声明一个字典类,如下例所示:

class D:Dictionary<int,string>{}

然后就用

D d=new D{{1,"something"},{2,"something else"}};

而不是Dictionary<int,string>为每个实例重复。

我已经在这个答案中使用了这种技术


2
还有“ D d”而不是“ var d”
Zukki 2015年

@Zukki显然!我在想什么 :)
Cristian Lupascu 2015年

选择:using D = System.Collections.Generic.Dictionary<int,string>;
托尔斯泰

10

您可以使用floatdouble文字来节省一些字节。

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;
递归

9

记住私人或公共存在于何处,例如:

class Default{static void Main()

相比于

public class Default { public static void Main()

5
并且总是只给全班同学一个字母:-)
Joey

2
哦,这Main还暗含了另一个好处:例如,与Java相比,不需要任何参数。
乔伊,

@Joey:也不需要公开。
R. Martinho Fernandes

1
@martinho〜您读了我的答案吗?;)在主

@Joey〜我试图将其保留为每个帖子一个;)... ...认为其他人会把有关main或class的帖子仅作为一封信发布。就像其他人一样,我将继续添加它。
jcolebrand

9

对于单行lambda表达式,可以跳过方括号和分号。对于单参数表达式,可以跳过括号。

代替

SomeCall((x)=>{DoSomething();});

采用

SomeCall(x=>DoSomething);

11
即使在生产代码上,我也永远不会写一个单参数lambda的括号。
R. Martinho Fernandes

我总是使用方括号,因为我喜欢将lambda分成多行以提高可读性。
朱莉安娜·佩尼亚

2
SomeCall(DoSomething)甚至更好
GreatAndPowerfulOz

9

循环播放:

变量声明:

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;)这既易于遵循,又更容易出错。
乔伊(Joey)

@Joey在这种情况下,我倾向于切换到while(++ i <max),它的长度相同,但更易于阅读。
ICR

ICR:取决于是否还可以在for头文件中放置另一个(较早的)语句,然后再保存一个字符。
Joey

您可以将两个声明都移回for子句,以节省1个字节。
递归

我喜欢更改for(;i<max;)while(i<max)。字节数相同,但对我来说看起来更干净。
Ayb4btu

8

在某些情况下,输出参数可以保存字符。这里有一个稍微做作的例子,一个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个字符。


8

在C#中,我们不允许if(n%2)检查是否n为偶数。如果这样做,我们得到一个cannot implicity convert int to bool。天真的处理方式是:

if(n%2==0)

更好的方法是使用:

if(n%2<1)

我用这个来获得一个字节这里

请注意,这仅适用于正数,因为-1%2==-1,即使使用此方法也可以考虑。


6

字符串插值

一个真正简单的节省空间的改进是插值。代替:

string.Format("The value is ({0})", (method >> 4) + 8)

仅用于$内联表达式:

$"The value is ({(method >> 4) + 8})"

这与C#6.0中的新表达式主体一起,应该可以使任何简单的字符串计算挑战在C#中变得非常容易。


3
另请注意,i+$" bottles of beer";它比短$"{i} bottles of beer"
aloisdg '16

1
@aloisdg在第一种情况下,您应该省去$
Metoniem '17

@Metoniem确实!我之所以这样做,是因为在我的原始案例中,我{i}前面有两个,中间是一个;)
aloisdg

@aloisdg啊,我明白了。是的,丢脸的评论无法编辑:(
Metoniem

6

使用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。我在这里使用这个技巧。您将不得不更改一些功能。示例:在线尝试!


1
不确定提示中是否还有其他内容,但在此示例中,您也可以使用currying ...s=>c=>...
TheLethalCoder

@TheLethalCoder确实可以!我将更新答案谢谢!
aloisdg '17

在这种情况下,您可以使用eta-reduction吗?像这样的东西:s=>s.Contains
corvus_192'1

请注意,“ untyped lambda”变体的C#和Java答案已不再受欢迎,您可能希望加入有关此meta post的讨论。建议的替代方法是(string s,char c)=>s.Contains(c)
VisualMelon



5

Compute实例方法System.Data.DataTable允许评估一个简单的字符串表达式,例如:

C#(Visual C#编译器),166字节

namespace System.Data
{
    class P
    {
        static void Main()
        {
            Console.Write(new DataTable().Compute("30*2+50*5/4",""));
        }
    }
}

在线尝试!

本身不是很“高尔夫”,但有时可能有用。


5

交换两个变量

通常,要交换两个变量,必须声明一个临时变量来存储值。看起来像这样:

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个字节。


不过,仅适用于数字,即使是元组和异或运算,也可能会遇到将整数应用于整数限制的风险。有时,其他数字类型也会遇到限制
仅限ASCII

4

使用LinqPad将使您有可能消除所有程序开销,因为您可以直接执行语句。(并且在codegolf中应该是完全合法的。没有人说您需要一个.exe)

使用.Dump()扩展方法完成输出。


.NetFiddle支持.Dump();)
aloisdg '16

4

了解您的运算符优先级的特殊情况!)

使用%用于紧密结合(有点)有限减法。这可以为您在减法周围节省一对括号,您想要将其乘以或除以某物。但请注意,它有严重的局限性。

代替

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字节)


4

如果您需要包含using全部属于同一层次结构的多个,通常将最长的一个用作会更短namespace

using System;
using System.Linq;
//Some code

vs:

namespace System.Linq
{
    //Some code
}

3

今晚在“沟渠中”发现的同时改进了一些高尔夫球代码...如果您有要处理的类,则可以在构造函数中进行工作以保存声明方法。

我在减少控制台应用程序时发现了这一点-因为有一个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个字符。



3

一起声明空字符串/匹配字符串

如果需要声明多个空/匹配字符串,则可以使用以下命令节省一些字节:

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吗?
corvus_192'1

@ corvus_192不-不幸的是没有。
Erresen
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.