JavaScriptでゴルフをするための一般的なヒントは何ですか?私は、少なくともある程度JavaScriptに固有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。
注:ECMAScript 6以降のゴルフのヒントも参照してください
JavaScriptでゴルフをするための一般的なヒントは何ですか?私は、少なくともある程度JavaScriptに固有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。
注:ECMAScript 6以降のゴルフのヒントも参照してください
回答:
非標準の方法で標準forループを使用できます
for ( a; b; c )
基本的に次と同等です:
a;
while ( b )
{
...
c;
}
そのため、while
ループを使用してコードを記述し、それをループ内のa,b,c
部分に分割することをお勧めしますfor
。
私が書いたいくつかの例:
for(x=y=n;!z;x--,y++)z=i(x)?x:i(y)?y:0
for(a=b=1;b<n;c=a+b,a=b,b=c);
複数の値を初期化またはリセットする場合、値を必要とするすべての変数にチェーンします。
a=b=1;
タイプをチェックせず、そのまま使用してください。parseInt()
コストがかかり10
ます。文字列からキャストする必要がある場合は、創造的です。
a='30';
b='10';
c = a + b; //failure
c = parseInt(a) + parseInt(b) //too long
c = -(-a-b); //try these
c = ~~a+~~b;
c = +a+ +b;
c = a- -b;
JavaScriptには自動セミコロン挿入があります。頻繁に使用してください。
可能な限り単一行またはパラメーターに押し込むことで、括弧を節約します。
a( realParam1, realParam2, fizz='buzz' )
a = a - 1;
foo(a);
そして
foo(a);
a = a - 1;
簡単に書き換えることができます
foo(--a);
そして
foo(a--);
それぞれ。
this
またはのself
代わりに使用するwindow
自明な2文字の節約。
これは、プロパティ名の長さとアクセス数の間のバランスのとれた行為です。a.longFunctionName()
ドット表記で2回呼び出す代わりに、名前を保存し、ブラケット表記で関数を呼び出す方が短くなります。
a.longFunctionName(b)
a.longFunctionName(c)
//42
-対-
a[f='longFunctionName'](b)
a[f](c)
//34
これは次のような機能には特に効果的であるdocument.getElementById
に低減することができますd[e]
。
注意:
ブラケット表記では6 + name.length
、最初のコストは文字です。以降の各アクセスには、3
文字のコストがかかります。
ドット表記の場合、すべてのアクセスにコストがかかりますname.length + 1
(の場合は+1 .
)。
次の場合にこのメソッドを使用し6 + name.length + (3 * (accesses - 1)) < accesses * (name.length + 1)
ます。
len =プロパティ名の長さ
i =利用するための最小アクセス
len | i
========
1 | ∞
2 | ∞
3 | 7
4 | 4
5 | 3
6 | 3
7 | 3
8+ | 2
アクセス数は複数のオブジェクトにまたがることもできます。.length
異なる配列で4回以上アクセスする場合、stringを保持する同じ変数を使用できます'length'
。
c = ~~a-~~b
する必要がありますc = ~~a+~~b
。また、あなたは暗黙的に使用して整数にキャストすることができます|0
例えば、Math.random()*6|0
。
a
およびb
が文字列の場合、+a+b
数値に変換して追加することができます。
d- -b
いつか私のコードに...
a.f=a.longfunctionname;a.f(b);a.f(c);a.f(d)
"alpha,bravo,charlie".split(",") // before
"alpha0bravo0charlie".split(0) // after
.split`...`
"alpha,bravo,charlie".split`,`
ランダムなブール値(0
または1
)が必要な場合:
new Date&1 // equivalent to Math.random()<0.5
ランダムな整数が必要な場合0 <= n < 1337
:
new Date%1337 // equivalent to Math.floor(Math.random()*1337))
これは、a Date
がエポックからミリ秒単位でJavaScriptに内部的に格納されているために機能し、整数演算を実行しようとするとnew Date
強制的に変換され123somebignumber456
ます。
もちろん、これらの「ランダムな」数値は、特に連続して複数回呼び出す場合は特にランダムではないので、注意してください。
get / setのオブジェクトリテラル形式を使用して、キーワードの使用を回避できますfunction
。
var obj = {
get f(){
console.log("just accessing this variable runs this code");
return "this is actually a function";
},
set f(v){
console.log("you can do whatever you want in here, passed: " + v);
}
};
1 && obj.f; // runs obj.[[get f]]
obj.f = Infinity; // runs obj.[[set f]](Infinity)
これはあまり知られておらず、あまり使用されていませんが、適切な状況で使用すると印象的です。引数を取らず、呼び出されたときに常に異なる数値を返す関数を考えてください。返された数値は計算に使用されます。
var a = [
Math.random()*12|0,
Math.random()*11|0,
Math.random()*10|0,
/* etc... */
];
通常、1文字の変数名を使用してこの関数を短縮できます。
var r=Math.random,a=[r()*12|0,r()*11|0,r()*10|0,r()*9|0,r()*8|0,r()*7|0,r()*6|0,r()*5|0];
長さを短くするより良い方法はabusingでvalueOf
、これにより呼び出しごとに2文字を節約できます。5回以上関数を呼び出す場合に便利です。
var r={valueOf:Math.random},a=[r*12|0,r*11|0,r*10|0,r*9|0r*8|0,r*7|0,r*6|0,r*5|0];
let a=[5,6,7,8,9,10,11,12].map(x=>x*Math.random()|0)
またはlet a=Array(7).map((_,i)=>i*Math.random()|0+5)
、それぞれ36バイトまたは42バイトが保存されます。
r()
たり、短くしたりすることはできますか?
r={valueOf:Math.random}
それはただの天才だ:D
長いif
ステートメントや三項演算子を使用するのではなく&&
、||
を使用してコードを短縮できます。例えば:
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;
になることができる
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
||
オペレータは、多くの場合、デフォルト値を設定するために、このように使用されます。
evt = evt || window.event;
これは書くことと同じです
if (!evt)
evt = window.event;
特定の文字の長い文字列を初期化する場合、長さn + 1の配列を作成することで初期化できます。ここで、nは文字を繰り返したい回数です。
// Create a string with 30 spaces
str = " ";
// or
str = Array(31).join(" ");
文字列が大きいほど、節約量は大きくなります。
単なる数値である文字列型を数値型に結合する代わりに、または結合するときに+
and ~
演算子を使用します。parseFloat()
parseInt()
var num = "12.6";
parseFloat(num) === +num; // + is 10 characters shorter than parseFloat()
var num2 = "12"
parseInt(num2) === +num2; // + is 8 characters shorter than parseInt()
var num3 = "12.6"
parseInt(num3) === ~~num3; // ~~ is 7 characters shorter than parseInt()
var num4 = "12.6"
parseInt(num4) === num4|0; // |0 is 7 characters shorter than parseInt()
ただし、これらの演算子を使用すると、他の型を結合できます(たとえば、true
になります1
)。空の文字列または空白のみを含む文字列はになり0
ます。ただし、これは特定の状況で役立つ場合があります。
str.repeat(count)
ユーザー入力を取得するためのprompt()呼び出しに変数を初期化する
n=prompt(i=5); // sets i=5 at the same time as getting user input
使用する代わりに
n=prompt();i=5;
副作用として、1文字を保存しながら、プロンプトウィンドウに入力値を表示します。
[1,2,3].join('',i=5)
、中括弧のペアを保存する場合のように、関数は便利です。
i=5,[1,2,3].join()
。
ネストされたforループを結合します。
// before:
for(i=5;i--;)for(j=5;j--;)dosomething(i,j)
// after:
for(i=25;i--;)dosomething(0|i/5,i%5)
i
/に異なる値を使用した例j
:
// before:
for(i=4;i--;)for(j=7;j--;)dosomething(i,j)
// after:
for(i=28;i--;)dosomething(0|i/7,i%7)
i*j
あり、除算/モジュラス演算子はi
およびの個々の値を取得しますj
。
Unicodeショートカット
大きなゴルフチャレンジでビルトインプロパティの地獄を使用する場合は、すべてのプロパティを1文字相当にエイリアスできます。
[Math,Number,S=String,Array].map(b=>
Object.getOwnPropertyNames(b).map((p,i)=>
b.prototype[S.fromCharCode(i+248)]=b[p]
)
)
上記のコードを実行した後、次のように使用できます。
"foo".Č(/.*/,'bar') // replaces foo with bar
これには118バイトかかるため、特定の状況では役に立たない可能性があります
それはブラウザに依存している可能性があり、それがwith(Array){join(foo),...}
使用されたプロパティとして変数よりも短いか定義されているかどうかはわかりませんwith(Array){j=join,m=map...}
が、それでも言及する価値があります。
Math Number String Array
ø toSource prototype prototype prototype
ù abs NaN quote join
ú acos POSITIVE_INFINITY substring reverse
û asin NEGATIVE_INFINITY toLowerCase sort
ü atan MAX_VALUE toUpperCase push
ý atan2 MIN_VALUE charAt pop
þ ceil MAX_SAFE_INTEGER charCodeAt shift
ÿ clz32 MIN_SAFE_INTEGER contains unshift
Ā cos EPSILON indexOf splice
ā exp isFinite lastIndexOf concat
Ă floor isInteger startsWith slice
ă imul isNaN endsWith filter
Ą fround toInteger trim isArray
ą log parseFloat trimLeft lastIndexOf
Ć max parseInt trimRight indexOf
ć min length toLocaleLowerCase forEach
Ĉ pow name toLocaleUpperCase map
ĉ random arguments normalize every
Ċ round caller match some
ċ sin search reduce
Č sqrt replace reduceRight
č tan split
Ď log10 substr
ď log2 concat
Đ log1p slice
đ expm1 fromCharCode
Ē cosh fromCodePoint
ē sinh localeCompare
Ĕ tanh length
ĕ acosh name
Ė asinh arguments
ė atanh caller
Ę hypot
ę trunc
Ě sign
ě cbrt
Ĝ E
ĝ LOG2E
Ğ LOG10E
ğ LN2
Ġ LN10
ġ PI
Ģ SQRT2
ģ SQRT1_2
Math
がないため、実際には機能しません.prototype
。Math
ただし、を削除すると、これらをすべて1バイト文字に割り当てる114バイトのスニペットになりました。ここで見つけることができます。
À
- ÿ
、まだ(JSがサポートしている)ISO-8859-1エンコーディングで1バイトごとです。Firefox 50では、残念ながらこの.localeCompare
メソッドはon ×
になりますが、通常は問題になりません。ソース
1
ループのすべての反復で変数を初期化する場合(たとえば、内側のループの外側のループで変数をリセットする)、次のように(この質問に対する私の回答から):
for(j=n-2;p=1,j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^
以下のような条件の結果であるためj++<=n
である1
(それが偽になった場合、ループはなくなりかかわら実行を停止しますので)その真の、あなただけの変数に直接条件を割り当てることができたときに:
for(j=n-2;p=j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^^^^^
通常、この方法を使用して2文字を保存できます。@ugoren
その答えにコメントでアイデア。
別の例では、外側のforループの式を使用して、このトリックを回答に適用しw=r=++c<S.length
、合計4文字を節約しました。
Spidermonkey(今のところ)特定のスクリプトを受け入れることができる場合、ECMAScript 6矢印関数を使用できます。次のようなコードを書く代わりに。
a.map(function(x){return x*2}) // function? return?
このように短縮できます。
a.map(x=>x*2)
NaNを確認する必要isNaN(x)
がある場合はx!=x
、を使用せず、を使用します。これは短く、動作します。
if(isNaN(x)){
if(x!=x){
これは、次の場合にのみ機能することに注意してくださいtypeof(x) === "number"
。たとえば文字列の場合、をisNaN("string")
返しますtrue
が、を"string" != "string"
返しますfalse
。これを指摘してくれたCyoceに感謝します!
isNaN("string")
returns true
、"string"!="string"
returns false
(明らかに)
if(!x){
検出している場合、に進むこともできますNaN
。
x
numberにキャストすると+x!=+x
、に相当しますがisNaN(x)
、2文字短くなります。次に、+"string"!=+"string"
trueを返します。
ビット単位の演算を使用して、数値をゼロに丸めます:
// do this
T=Math.random()*6+1|0
// or do this
T=~~(Math.random()*6+1)
(出典:ランダムダイスチップ)
オペレーターの優先順位により、プログラムのどちらが短くなるかが決まります。
n=prompt()|0
ます。
Math.floor
非常に遅いです。ほとんど使用しないでください
ループのヒントI
最後に使用した時間を1
変更することで、ループ時にキャラクターを保存できますi
。
//not so god
for(i=0;i<3;i++){
alert(i);
}
//best
for(i=0;i<3;){
alert(i++);
}
注:でも動作し--
ます(ただし、無限ループを回避するためにループを適宜変更します)
ループのヒントII
インクリメント演算子と値で遊んで1つのキャラクターを保存できる特定のシナリオがあります。
for(i=0;i++<9;)
for(i=0;++i<10;)
注:などの場合、注意を払う必要があります0 to -1
。そして9 to 10, 99 to 100
、あなたがキャラクターを救う方法を見つけるまで遊んでください
^
代わりに、!=
または==
整数と比較するときに使用します//x!=3?a:b
x^3?a:b
//x==3?a:b
x^3?b:a
//Math.ceil(n)
n%1?-~n:n
//Math.floor(n)
~~n
0|n
//Math.abs(n)
n<0?-n:n
//Math.round(n)
n+.5|0
//Math.min(x,y)
x<y?x:y
//Math.max(x,y)
y<x?x:y
-
代わりに単純に使用でき!=
ます。たとえば、次n!=1?a:b
と同等ですn-1?a:b
注目に値するのは、いくつかのインスタンスでゼロの代わりに文字列を使用して、ループのあちこちで数バイトを保存できることです。
s='';for(i=0;i++<9;)s+=i
for(i=s='';i++<9;)s+=i
// s="123456789", i=10
たとえそうであっても、誰もそれについて言及していませんでした。
使用している場合、Math.min()
またはこれMath.max()
を行うことで6文字を保存できる場合:
Math.min(a,b) // 13 chars
a<b?a:b // 7 chars
Math.max(a,b)
a>b?a:b
私は代替案Math.floor()
が投稿されたことを知っていますが、他のものはどうですか?
Math.floor(x) //before
0|x //after
Math.round(x) //before
0|x+.5 //after
Math.ceil(x) //before
x%1?-~x:x //after - credits to @Tomas Langkaas
0|x+1
上限を求める数値が既に整数である場合は、単純に1を加算することに注意してください。(ほとんど)安全な代替手段はですが0|x+1-1e9
、これは3バイト短くなっています。
0|x+1-1e-9
か?
x%1?-~x:x
(9文字)がより適切な代替手段です。ただし、フローリングの選択肢0|x
およびのように、~~x
正の数に対してのみ機能します。
三項演算子を使用して2つの数値のいずれかを選択し、条件がブールまたは数値の 1 or 0
場合、代わりに数学演算を実行できます。
(x ? num1 : num2) conclusions:
1)if num1 equals num2, there ARE savings
2)if num1 is (+1) or (-1) than num2, there ARE savings
3)if either num1 or num2 equals to 0, there ARE savings
4)it is MORE LIKELY to find greater savings on num1>num2 instead of num1<num2
5)in method (*A) and (*B), savings are NOT GUARANTEED
a)num1>num2
i)(num1==(num2+1))
ex1: (x?5:4) to (x+4)
ex2: (x?8:7) to (x+7)
ii)num2==0
ex1: (x?3:0) to (x*3)
ex2: (x?7:0) to (x*7)
iii)
(*A) or (*B) //one might be shorter
b)num1<num2
i)((num1+1)==num2)
ex1: (x?4:5) to (5-x)
ex2: (x?7:8) to (8-x)
ii)num1==0
ex1: (x?0:3) to (!x*3)
ex2: (x?0:7) to (!x*7)
iii)
(*A) or (*B) //one might be shorter
c)num1==num2
i)
ex1: (x?5:5) to (5)
ex2: (x?-3:-3) to (-3)
(*A) use ((x*(num1-num2))+num2)
ex1: (x?8:4) to ((x*4)+4)
ex2: (x?4:8) to ((x*-4)+8)
ex3: (x?6:-4) to ((x*10)-4)
ex4: (x?-4:6) to ((x*-10)+6)
ex5: (x?4:-6) to ((x*10)-6)
ex6: (x?-6:4) to ((x*-10)+4)
ex7: (x?-5:-9) to ((x*4)-9)
ex8: (x?-9:-5) to ((x*-4)-5)
(*B) use ((!x*(num2-num1))+num1)
ex1: (x?8:4) to ((!x*-4)+8)
ex2: (x?4:8) to ((!x*4)+4)
ex3: (x?6:-4) to ((!x*-10)+6)
ex4: (x?-4:6) to ((!x*10)-4))
ex5: (x?4:-6) to ((!x*-10)+4)
ex6: (x?-6:4) to ((!x*10)-6)
ex7: (x?-5:-9) to ((!x*-4)-5)
ex8: (x?-9:-5) to ((!x*4)-9)
注意:これに加えて、あなたが不要な削除する必要があります0-
、+0
、+-
など
注2:動作するために必要であるように(x) !== (x?1:0)
、孤立したケースがx
ありますtypeof === "number"
。ただし、この場合は問題(-x)
なく機能します。
注3:貯蓄が見つからない場合は、前者を使用してください(x?y:z)
以前は、メソッドBがAに勝つことはできないと思っていましたが、例外は存在します。
(x?97:100) //original
(-3*x+100)
(3*!x+97)
私たちのために単純化するgithubプロジェクトを作成しました(jsFiddleデモ)
void 0
(関数ではなく、キーワード)は値ではなく、単にを返しますundefined
。
a
それを動作させるための1または0のいずれかでなければなりません
tl; dr: ES6機能を使用してください!
Doc:https : //developer.mozilla.org/en/docs/Web/JavaScript/Reference/arrow_functions
例:
s = x => x*x
// s = function (x) {
// return x * x;
// }
数値をブール値に変換する方法の助けを借りて、数値を比較する方法:
何かが正の数に等しいかどうかを確認する場合は、その量を減算しif
、else
ブロック内およびブロック内にあったものを逆にすることができます。
//simplified examples:
x==3?"y":"n"; <- 13 Chars
x-3?"n":"y"; <- 12 Chars
//expanded examples:
if(x==3){
yes();
}else{
no();
}
if(x-3){
no();
}else{
yes();
}
また、負の数(*とは異なる-1
)と比較したい場合は、単に減算する代わりにこの数を加算するだけです。
*まあ、あなたは確かに使うことができますが、あなたx.indexOf(y) + 1
の特別な場合には代わり-1
に使う機会があります~x.indexOf(y)
。
Mozillaの非標準の「式クロージャ」機能を使用して、SpiderMonkey / FirefoxまたはRhinoエンジンでのみ動作する必要があるスクリプトに多くの文字を保存します。例えば、
function foo(){return bar}
になる
function foo()bar
このようなトリックの詳細については、Stack Overflowページをご覧ください。
->bar
let foo = () => bar;
上記golfedコードよりも皮肉短いです。
foo=_=>bar
さらに短い。
書く代わりにをtrue
使用できます!0
。
!1
ためfalse
。
1
for true
と0
forを使用することfalse
です。
ブール値への変換:
if(b){b=true}else{b=false}
b=b?true:false;
b=b?!0:!1;
b=!!b;
注:これは変化し0
、""
、false
、null
、undefined
とNaN
するfalse
(と他のすべてtrue
)
var
か?JavaScriptのゴルフコードを関数にするか、何かを直接出力する必要がありますか?私はこれが大きな違いを生むと思います。