C#でゴルフをするための一般的なヒントは何ですか?私は、少なくともC#に固有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。回答ごとに1つのヒントを投稿してください。
-marcogのアイデアから借りた;)
C#でゴルフをするための一般的なヒントは何ですか?私は、少なくともC#に固有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。回答ごとに1つのヒントを投稿してください。
-marcogのアイデアから借りた;)
回答:
安全に文字列にネイティブにキャストできる数値やその他の型の.ToString()
使用+""
を使用する代わりに。
.ToString() <-- 11 chars
+"" <-- 3 chars
(1+"").DoSomethingWith1String();
String.Concat(object)
、仮想呼び出しではなく、引数で静的を呼び出すことに注意してくださいobject.ToString()
。空の文字列にConcat
明示的に変換null
します(参照ソースを参照)。「ネイティブキャスト」は行われていません。このような変換を行うことができます。場合によっては、結果があまり役に立たない可能性があります。(しかし、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.
、メソッド呼び出しを省くことによる節約よりも長くなりますが、はい、それはオプションですが、償却するために多くの呼び出しを必要とする多額の初期費用がかかります。
LINQを使用する場合Select
、ラムダを作成する代わりにメソッドを直接渡すことができます。
だから、代わりに
foo.Select(x=>int.Parse(x))
使用できます
foo.Select(int.Parse)
直接。
(TimwiのC#回答の 1つを改善すると最近発見されました。)
C#でコンパイル可能な最小のプログラムは29文字であることに注意してください。
class P
{
static void Main()
{
}
}
だからあなたの長さからそれを削除することから始めて、それがどれくらいかかるかについてあなたの答えを判断してください。C#は、ほとんどの[code-golf]
問題の中心である入力の印刷または読み取りに関して、他の言語と競合することはできません。そのため、心配する必要はありません。C#ゴルファーとして、あなたは本当に言語と競争しています。
その他の留意事項:
if
括弧を削除するために、可能であればすべてのループとステートメントを1行に減らしてください。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
が長い場合は特に、読みやすいオプションにはほど遠い場合があります。IMO、副作用をうまく伝えることもできません。のif (i < 1)
ようなif (SendEmail(recipient))
ものが副作用の成功に応じてtrue / falseを返す場合、if / then表記を好みます。
j=i<1?1:0;
十分です。
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では、ラムダを使用して関数を定義できます。
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>
コードでジェネリックを少なくとも2回使用する必要がある場合は、次の例のように辞書クラスを宣言できます。
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
and 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とは対照的に、引数は不要です。
1行のラムダ式の場合、括弧とセミコロンをスキップできます。1パラメーター式の場合、括弧をスキップできます。
の代わりに
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回だけ使用する必要がある場合は、-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;)
は、フォローしやすく、誤解しにくいものです。
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}
、前に2 つ、中央に1つあったので、それを許可しました;)
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つのパラメーターがある場合に役立ちます。空の未使用変数の_
方が適しています。これに関するメタ投稿を参照してください。ここでこのトリックを使用します。機能を少し変更する必要があります。例:オンラインでお試しください!
s=>c=>...
s=>s.Contains
。
(string s,char c)=>s.Contains(c)
クラス名を1文字のみにします。上の強化C#でコードゴルフのためのヒント私達はから行きます
class Default{static void Main()
に
class D{static void Main()
この場合、さらに6文字がノックアウトされます。
のCompute
インスタンスメソッドによりSystem.Data.DataTable
、たとえば次のような単純な文字列式を評価できます。
namespace System.Data
{
class P
{
static void Main()
{
Console.Write(new DataTable().Compute("30*2+50*5/4",""));
}
}
}
それ自体は「ゴルフ」ではありませんが、時には役に立つかもしれません。
通常、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バイト節約されます。
使用%
タイト結合(やや)限られた減算に。これにより、減算を囲む括弧のペアを節約でき、その結果を乗算または除算する必要があります。しかし、注意してください、それは深刻な制限があります。
の代わりに
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バイトを必要とします)
using
同じ階層からすべて落ちる複数のを含める必要がある場合、最も長いものを次のように使用する方が短いことがよくありnamespace
ます。
using System;
using System.Linq;
//Some code
対:
namespace System.Linq
{
//Some code
}
いくつかのゴルフコードを改善しながら、今夜「溝の中」で発見されました。処理のためのクラスがある場合は、コンストラクタで作業を行ってメソッドの宣言を保存できます。
コンソールアプリケーションを縮小しているときにこれを発見しました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 を使用したすばらしい例に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で好きですか?