C#でのコードゴルフのヒント


62

C#でゴルフをするための一般的なヒントは何ですか?私は、少なくともC#に固有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。回答ごとに1つのヒントを投稿してください。

-marcogのアイデアから借りた;)


ベストヒント=>チャレンジの最長回答を送信したくない場合は、.NETの横にあるものを使用してください。.NETは非常に冗長で、IDEに入力を許可するように設計されています。IDE松葉杖を持っている限り、これは一般的なプログラミングに聞こえるほど悪くはありませんが、コードゴルフではその戦略は確かに失敗します。
クロー14

カレンダーの写真を私に許してください、それは私がすぐに見つけることができるすべてでした。
地下

回答:


59

安全に文字列にネイティブにキャストできる数値やその他の型の.ToString()使用+""を使用する代わりに。

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

5
これはJSでも機能します。
チョイス

1
(1+"").DoSomethingWith1String();
あとで

1
文字列が必要な場合、通常は保存します。他のほとんどの使用法では、ToString()をネイティブに推測できます
...-jcolebrand

1
これは実際にはString.Concat(object)、仮想呼び出しではなく、引数で静的を呼び出すことに注意してくださいobject.ToString()。空の文字列にConcat明示的に変換nullします(参照ソースを参照)。「ネイティブキャスト」は行われていません。このような変換を行うことができます。場合によっては、結果があまり役に立たない可能性があります。(しかし、nullの動作はそうかもしれません)。
VisualMelon

1
代替- 文字列補間$"{n}"
Andriy Tolstoy

41

namespace System特定のクラスへのアクセスを短縮できるように、プログラムを意図的に配置しました。比較する

using System;using M=System.Math;

namespace System{using M=Math;

9
1回の使用で問題が解決する場合は、クラス/関数を完全に修飾することをお勧めします。これは、System名前空間内のアイテムに対してのみ、複数回何かを呼び出す必要がある場合にのみ役立ちます。
ニックラーセン

また、単に行うことができますusing System;class P...
ldam

@Logan:これはusing System;、同じ名前空間内のクラスのエイリアスを持つだけではなく、ここで示した方法よりも短いものです。
ジョーイ

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.

29

LINQを使用する場合Select、ラムダを作成する代わりにメソッドを直接渡すことができます。

だから、代わりに

foo.Select(x=>int.Parse(x))

使用できます

foo.Select(int.Parse)

直接。

TimwiのC#回答の 1つを改善すると最近発見されました。)


2
FWITWこれはη削減
-ThreeFx


5
私たちのより実用的なことに、それは単に短いです:-þ
Joey

23

C#でコンパイル可能な最小のプログラムは29文字であることに注意してください。

class P
{
    static void Main()
    {   
    }
}

だからあなたの長さからそれを削除することから始めて、それがどれくらいかかるかについてあなたの答えを判断してください。C#は、ほとんどの[code-golf]問題の中心である入力の印刷または読み取りに関して、他の言語と競合することはできません。そのため、心配する必要はありません。C#ゴルファーとして、あなたは本当に言語と競争しています。

その他の留意事項:

  • if括弧を削除するために、可能であればすべてのループとステートメントを1行に減らしてください。
  • stdinとコマンドラインの間にオプションを指定する場合は、常にコマンドラインを使用してください!

これには通常、三項も含まれます;)
jcolebrand

1
As a C# golfer, you're really competing against the language 信じられないほど関連
ドルカハン

1
実際には、そうではありません。static int Main()28文字のコンパイルも使用します。
メトニエム


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
私は、2番目のケースが一般的にこのようなものについて本質的に読みやすいと感じる唯一のものですか?私はそれを定期的にしています。さらに、null状態(文字列など)を回避する必要がある場合は、次のようなことを行いますvar x = input ?? "";
結合

よりi < 1複雑なステートメントである場合や、名前jが長い場合は特に、読みやすいオプションにはほど遠い場合があります。IMO、副作用をうまく伝えることもできません。のif (i < 1)ようなif (SendEmail(recipient))ものが副作用の成功に応じてtrue / falseを返す場合、if / then表記を好みます。
ニックラーセン

11
2番目のケースでは括弧は必要ありません- j=i<1?1:0;十分です。
ダンコドゥルビッチ

3
この質問では、C#にある程度固有のヒントを求めています。これは、すべての言語ヒントに含まれています
ピーターテイラー14年

4
@PeterTaylor私はあなたがリンクされたスレッドが作成されただけでなく前に、3年以上前にこの質問に答え
Nellius

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

@mellamokbそうです、ありがとう!一定。
クリスチャンルパスク

1
できませんかauto r=Console.ReadLine;
クラウディ14

2
@claudiuいいえ、残念ながらideone.com/jFsVPXではありませ
クリスティアン・ルパスク14

@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
それは本当に恐ろしいです...私はそれが大好きです!
アレックスReinking

神聖ながらくたこれは天才です、私は実際に配列をループしながら文字を保存しました
-Gaspa79

これは本当に悪です!
GreatAndPowerfulOz

13

C#6でラムダを使用して関数を定義する

C#6では、ラムダを使用して関数を定義できます。

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

これは、次のような関数を定義するよりも短いです。

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

3
C#6は、まったく新しい範囲のコードゴルフを可能にします
-jcolebrand

C#7では、これを別の関数内で実行してローカル関数を作成できます。これはゴルフ中に役立つとは思いませんが、それでもまだ知っておくべきすてきなトリックです。
-TehPers

1
正式にはラムダではありません。それはだ表現ボディのメンバー
再帰的

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

私はシャミールの秘密の共有の挑戦に対する私の答えでこのトリックを使用します。
aloisdg

最適化をオンにしてienumerableを反復しない場合、文字列部分が実行されるとは思わない。.ToArray();を実行するまで失敗しました。それ以外に、驚くべきヒント!
-Gaspa79

はい、enumerablesは遅延していますが、文字列を含むものだけでなく、3つの例すべてに当てはまります。
ぼんやりした

11

Dictionary<TKey, TValue>コードでジェネリックを少なくとも2回使用する必要がある場合は、次の例のように辞書クラスを宣言できます。

class D:Dictionary<int,string>{}

そして、単に使用する

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

Dictionary<int,string>インスタンス化ごとに繰り返すのではなく。

私はこの答えでこの手法を使用しました


2
また、「var d」の代わりに「D d」
ズッキー

@Zukki明らかに!私が考えていたことは何でしょう?:)
クリスチャンルパスク

代替案:using D = System.Collections.Generic.Dictionary<int,string>;
Andriy Tolstoy

10

floatand 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;
再帰的な

9

次のように、プライベートまたはパブリックの固有の場所を覚えておいてください。

class Default{static void Main()

と比較して

public class Default { public static void Main()

5
そして、クラスは常に1文字だけにします:
ジョーイ

2
ああ、ここで暗示されているもう1つの素晴らしいことですMain。たとえば、Javaとは対照的に、引数は不要です。
ジョーイ

@Joey:パブリックである必要もありません。
R.マルティーニョフェルナンデス

1
@martinho〜私の答えを読んでくれましたか?;)メインの
非公開

@Joey〜投稿ごとに1つにしようとしていた;)...他の誰かがメインまたはクラスが1文字だけであると投稿するだろうと考えました。他に誰も持っていないように見えるので、先に進んでそれも追加します。
jcolebrand

9

1行のラムダ式の場合、括弧とセミコロンをスキップできます。1パラメーター式の場合、括弧をスキップできます。

の代わりに

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

つかいます

SomeCall(x=>DoSomething);

11
実稼働コード上であっても、1パラメーターラムダのかっこを書くことはありません。
R.マルティーニョフェルナンデス

読みやすくするためにラムダを複数の行に分割するのが好きなので、常に括弧を使用しています。
ジュリアナペーニャ

3
SomeCall(DoSomething)さらに良いです
GreatAndPowerfulOz

9

ループ:

変数宣言:

int max;
for(int i=1;i<max;i++){
}

になる:

int max,i=1;
for(;i<max;i++){
}

また、i変数を1回だけ使用する必要がある場合は、-1(ループの状況に応じて0)から開始し、インラインでインクリメントできます。

int max,i=1;
for(;i<max;i++){
  Console.WriteLine(i);
}

int max,i=1;
for(;i<max;){
  Console.WriteLine(++i);
}

そして、それは1文字減り、コードも少し難読化します。次のiように、最初の参照に対してのみそれを行います:(1文字の最適化はそれほど重要ではありませんが、役立ちます)

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これらの場合、同じ長さで読みやすいwhile(++ i <max)に切り替える傾向があります。
ICR

ICR:forヘッダーに別の(以前の)ステートメントを配置できるかどうかに依存します。これにより、文字が再び保存されます。
ジョーイ

a1バイトを節約するために、両方の宣言をfor句に戻すことができます。
再帰的

に変更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バイトを増やしました

これは正の数に対してのみ機能することに注意してください-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

1
@aloisdgただし、最初のケースでは、除外する必要が$あります。
メトニエム

@Metoniem本当に!私の元のケースでは{i}、前に2 つ、中央に1つあったので、それを許可しました;)
aloisdg

@aloisdgああ、なるほど。ええ、恥のコメントは編集できません:(
Metoniem

6

C#ラムダを使用します。PPCGでは入出力にラムダが使用できるため、それらを使用する必要があります。

古典的なC#メソッドは次のようになります。

bool Has(string s, char c)
{
    return s.Contains(c);
}

ラムダとして、

Func<string, char, bool> Has = (s, c) => s.Contains(c);

匿名のラムダも許可されます。

(s, c) => s.Contains(c)

すべてのノイズを取り除き、焦点を合わせます!

更新:

@TheLethalCoderのコメントとしてカリー化することで、さらに改善できます。

s => c => s.Contains(c);

@Felix Palmenによるカリングの例:WPAキーの計算方法

正確に2つのパラメーターがある場合に役立ちます。空の未使用変数の_方が適しています。これに関するメタ投稿を参照してください。ここでこのトリックを使用します。機能を少し変更する必要があります。例:オンラインでお試しください!


1
ヒントのどこにあるかはs=>c=>...
わかり

@TheLethalCoder本当にできる!回答を更新しますありがとうございます!
-aloisdg

この場合、イータリダクションを使用できますか?このようなもの:s=>s.Contains
corvus_192

「型指定されていないラムダ」の種類のC#とJavaの回答は好意的ではないことに注意してください。このメタ投稿の議論に参加したいかもしれません。推奨される代替案は(string s,char c)=>s.Contains(c)
-VisualMelon




5

2つの変数の交換

通常、2つの変数を交換するには、値を格納する一時変数を宣言する必要があります。これの線に沿って何かのように見えるでしょう:

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

最後の3つは数値に対してのみ機能し、ASCIIのみが指摘しているように、最後の2つはArithmeticOverflow例外になる可能性があります。上記はすべて12バイトで、最初の例と比較して4バイト節約されます。


ただし、数値にのみ適用され、それでもタプルやxor以外のものはすべて、整数にこれを適用している整数の制限に達するリスクがあります。時折、他の数の種類があまりにも限界に実行されます
ASCIIのみ

4

LinqPadを使用すると、ステートメントを直接実行できるため、プログラムのオーバーヘッドをすべて削除できる可能性があります。(そして、それはcodegolfで完全に合法でなければなりません... .exeが必要だと言う人はいません)

出力は、.Dump()拡張メソッドを使用して行われます。


.NetFiddleサポート.Dump();)
aloisdg

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

対:

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

@ corvus_192いや-残念ながらありません。
エレセン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.