ECMAScript 6以降でのゴルフのヒント


88

これは他の「<...>でのゴルフのヒント」に似ていますが、特にECMAScript 6以降で作成されたJavaScriptの新しい機能を対象としています。

JavaScriptは、本質的に、非常に冗長な言語であるfunction(){}.forEach()などの配列、配列への配列のようなオブジェクトなど、に文字列を変換するスーパーbloatsとゴルフのための健康的ではありません。

一方、ES6 +には、非常に便利な機能があり、フットプリントが削減されています。x=>y[...x]などはほんの一例です。

コードから余分なバイトを削除するのに役立つ素敵なトリックを投稿してください。

注:ES5のトリックは、JavaScriptのゴルフのヒントで既に利用可能です。このスレッドへの回答は、ES6および他の将来のESバージョンでのみ利用可能なトリックに焦点を当てる必要があります。

ただし、このスレッドは、現在ES5機能を使用してゴルフをしているユーザー向けです。回答には、ES6の機能を理解し、ES5コーディングのスタイルにマッピングするのに役立つヒントも含まれている場合があります。

回答:


42

スプレッド演算子 ...

spreadオペレーターは、配列値をコンマ区切りリストに変換します。

ユースケース1:

関数がリストを期待する場所で配列を直接使用する

list=[1,2,3]
x=Math.min(...list)
list=[10,20], a.push(...list) // similar to concat()

ユースケース2:

反復可能(通常は文字列)から配列リテラルを作成します

[...'buzzfizz'] // -> same as .split('')

ユースケース3:

関数の可変数の引数を宣言する

F=(...x) => x.map(v => v+1)
// example: F(1,2,3) == [2,3,4]

mozilla docを参照してください


3
今、私はここで下票を持っています。明らかに誰かがコメントを残し、何...説明するにはあまりにも恥ずかしがり屋であること、このヒントでひどく間違って何かを指摘
edc65

大丈夫そうです。たぶん、セミコロンの不足だったのでしょうか?;)(ところで、Rubyの
スプラットの

関数シグネチャにもユースケースがあることを追加できます:)
Felix Dombek

Misclickはdownvoteするつもりはありませんでした
スタン・ストラム

@StanStrumそれが起こる。最終的にあなたの投票を変更できるように、この投稿に小さな更新を行います(または、すでに変更しましたか?)
edc65

21

入社以来ここで学んだトリック

私の主なプログラミング言語はJSで、ほとんどがES6です。1週間前にこのサイトに参加して以来、仲間のメンバーから多くの有用なトリックを学びました。ここでそれらのいくつかを組み合わせています。コミュニティへのすべてのクレジット。

矢印関数とループ

矢印関数は多くのバイトを節約することを知っています

function A(){do something} // from this
A=a=>do something // to this

しかし、あなたはいくつかのことを覚えておく必要があります

  • 使用クラブ複数の文にしてみ,つまり(a=b,a.map(d))返される値は、最後の式で、ここで-a.map(d)
  • あなたの場合はdo something一部が複数の文がある、あなたは周囲追加する必要が{}ブラケットを。
  • {}角かっこがある場合は、明示的なreturnステートメントを追加する必要があります。

上記のことは、ループが関係している場合に多く当てはまります。のようなもの:

u=n=>{for(s=[,1,1],r=[i=1,l=2];c=l<n;i+=!c?s[r[l++]=i]=1:1)for(j of r)c-=j<i/2&s[i-j];return n>1?r:[1]}

ここでは、復帰のために少なくとも9文字を無駄にしています。これは最適化できます。

  • forループを避けるようにしてください。.mapまたは.every.some代わりに使用します。マッピングしているのと同じ配列を変更する場合、失敗することに注意してください。
  • ループをクロージャー矢印関数でラップし、メイン矢印関数を単一のステートメントとして変換します。

したがって、上記は次のようになります。

u=n=>(s=>{for(r=[i=1,l=2];c=l<n;i+=!c?s[r[l++]=i]=1:1)for(j of r)c-=j<i/2&s[i-j]})([,1,1])|n>1?r:[1]

削除された文字: {}return

追加されたキャラクター: (){}>|

変数を正しく設定するクロージャーメソッドを呼び出す方法に注意してください。nクロージャーメソッドは何も返さない(つまり返すundefined)ので、ビット単位でまたはそれを返しn、外側の矢印関数の単一のステートメントで配列をすべて返しますu

コンマとセミコロン

それを避けましょう

ループ内で変数を宣言する場合、または前のセクションで述べたように、,分離したステートメントを使用して単一のステートメント矢印関数を使用する場合は、かなり巧妙なトリックを使用してそれらを回避する,;、最後の数バイトを削ることができます。

次のコードを検討してください。

r=v=>Math.random()*100|0;n=r();m=r();D=v=>A(n-x)+A(m-y);d=0;do{g();l=d;d=D();....

ここでは、多くの変数を初期化するために多くのメソッドを呼び出しています。各初期化は,またはを使用してい;ます。これは次のように書き換えることができます。

r=v=>Math.random()*100|0;n=r(m=r(d=0));D=v=>A(n-x)+A(m-y);do{d=D(l=d,g());....

メソッドが渡された変数を気にしないという事実をどのように使用し、その事実を使用して3バイトを削るのかに注意してください。

その他

.search の代わりに .indexOf

どちらも同じ結果にsearchなりますが、短いです。検索には正規表現が必要ですが、賢明に使用してください。

`テンプレート文字列`

これらは、特定の条件に基づいて1つ以上の文字列部分を連結する必要がある場合に非常に便利です。

次の例を使用して、JSでクインを出力します

(f=x=>alert("(f="+f+")()"))()

(f=x=>alert(`(f=${f})()`))()

2つの逆引用符( `)内の文字列であるテンプレート文字列では、a内のすべてが${ }コードとして扱われ、評価された結果が文字列に挿入されます。

あとでいくつかのトリックを投稿します。ハッピーゴルフ!


1
.searchは短くなり、可能な場合はそれを使用してください!ただし、.indexOfと同じではありません。.search regexpでは、文字列ではなくが必要です。試してみてください'abc'.search('.')
edc65

@ edc65更新されました!
オプティマイザー14

インスタンスメソッドを使用して、元の配列を変更できます。2番目は現在のインデックスで、3番目は反復される配列です。
イサイアメドウズ

8
「1週間前にサイトに参加しました」-21.4k rep
...-GamrCorps

2
同様に.map、再帰はforループを式に変換するのに役立つ別の手法です。
ニール

20

プロパティの短縮形を使用する

プロパティの短縮形を使用すると、変数を配列の値に設定できます。

a=r[0];b=r[1] // ES5
[a,b]=r       // ES6 - 6 bytes saved

これは次のようにも使用できます。

a=r[0],b=r[2] // ES5
[a,,b]=r      // ES6 - 5 bytes saved

これを使用して変数を逆にすることもできます。

c=a,a=b,b=c // ES5 - uses extra variable
[b,a]=[a,b] // ES6 - not shorter, but more flexible

これを使用してslice()機能を短縮することもできます。

z = [1, 2, 3, 4, 5];

a=z.slice(1) // a = [2,3,4,5]; ES5
[,...a]=z    // a = [2,3,4,5]; ES6

基本変換

ES6は、フォームBase-2(バイナリ)およびBase-8(8進数)を10進数に変換するはるかに短い方法を提供します。

0b111110111 // == 503
0o767       // == 503

+2進数、8進数、または16進数の文字列を10進数に変換するために使用できます。あなたは使用することができ0b0oおよび0xそれぞれ2進数、8進数、および進のために、:

parseInt(v,2) // ES5
+('0b'+v)     // ES6 - 4 bytes saved; use '0o' for octal and '0x' for hex
'0b'+v-0      // Shorter, but may not work in all cases
              // You can adapt this your case for better results

これを7回以上使用している場合は、使用parseIntして名前を変更する方が短くなります。

(p=parseInt)(v,2)

今すぐpに使用することができparseInt、あなたに長期的に多くのバイトを保存し、。


基本的な変換のトリックは素晴らしいですが、変換番号はリテラルではなく変数の形になる可能性が高く、その場合、はるかに長くなります。
オプティマイザー

1
'0x'+v-0はさらに短くなりますが、一部のシナリオではうまく機能しない場合があります。
ETHproductions

1
ちなみに、0767(ES5)は0o767(ES6)表記よりも短くなっています。
カミロマーティン

@CamiloMartin 0767は非標準の拡張機能であり、strictモードでは明示的に禁止されています。
オリオール

1
@Oriol strictモードは悪いミームでした。それはパフォーマンスを助けず、本当に良いコードを書くことを強制しませんでした、とにかくデフォルトになることはありませんでした。0-接頭辞付きの8進リテラルはどこにも行かず、有効なecmascriptです0o
カミロマーティン

19

関数で文字列テンプレートを使用する

引数として1つの文字列を持つ関数がある場合。()式がない場合は、省略できます。

join`` // Works
join`foobar` // Works
join`${5}` // Doesn't work 

9
注意してください、これは実際に配列を渡します。fun`string` 同じであるfun(["string"])ではありません、fun("string")。これは、などの文字列にキャストする関数ではalert問題ありませんが、他の関数では問題が発生する可能性があります。詳細については、MDNの記事
-Cyoce

5
クイックリファレンス:fun`foo${1}bar${2}baz呼び出しと同等ですfun(["foo","bar","baz"],1,2)
-Cyoce

14

配列内包表記(Firefox 30-57)

注:配列内包表記は標準化されることはなく、Firefox 58では廃止されました。ご自身の責任で使用してください。


もともと、ECMAScript 7の仕様には、多数の新しいアレイベースの機能が含まれていました。これらのほとんどは最終版にそれをしなかったものの、Firefoxのサポート(ED)、これらの機能の可能性が最も大きい:置き換えることができます空想新しい構文.filter.mapfor(a of b)構文。以下に例を示します。

b.filter(a=>/\s/.test(a)).map(a=>a.length)
[for(a of b)if(/\s/.test(a))a.length]

ご覧のとおり、2行目はそれほど大きくはありませんが、2行目はかさばるキーワードと矢印関数が含まれていません。しかし、これは注文を説明するだけ.filter().map()です。.map().filter()代わりに持っている場合はどうなりますか?それは本当に状況に依存します:

b.map(a=>a[0]).filter(a=>a<'['&&a>'@')
[for(a of b)if(a<'['&&a>'@')a[0]]

b.map(a=>c.indexOf(a)).filter(a=>a>-1)
[for(a of b)if((d=c.indexOf(a))>-1)d]

b.map(a=>a.toString(2)).filter(a=>/01/.test(a))
[for(a of b)if(/01/.test(c=a.toString(2)))c]

または、どちらか .map または どちらが必要.filterですか?まあ、それは通常あまり良くないことがわかります:

b.map(a=>a.toString(2))
[for(a of b)a.toString(2)]

b.filter(a=>a%3&&a%5)
[for(a of b)if(a%3&&a%5)a]

したがって、私のアドバイスは、通常は.map and を使用する場合に配列内包表記を使用することですが、.filterどちらか一方だけではありません。

文字列の内包表記

ES7の内包表記のいいところは、以下のようなアレイ固有の機能とは異なり、ということです.map.filter、彼らは上で使用することができます任意の反復可能なオブジェクトだけでなく、配列。これは、文字列を扱うときに特に役立ちます。たとえばc、文字列の各文字を次のように実行する場合c.charCodeAt()

x=>[...x].map(c=>c.charCodeAt())
x=>[for(c of x)c.charCodeAt()]

それはかなり小さなスケールで2バイト節約されます。また、文字列内の特定の文字をフィルタリングする場合はどうなりますか?たとえば、これは大文字のみを保持します。

x=>[...x].filter(c=>c<'['&&c>'@')
x=>[for(c of x)if(c<'['&&c>'@')c]

うーん、それは短くありません。しかし、2つを組み合わせると:

x=>[...x].filter(c=>c<'['&&c>'@').map(c=>c.charCodeAt())
x=>[for(c of x)if(c<'['&&c>'@')c.charCodeAt()]

すごい、10バイト全部節約できました!

文字列内包表記のもう1つの利点は、ハードコーディングされた文字列が余分なバイトを節約することですof

x=>[...'[](){}<>'].map(c=>x.split(c).length-1)
x=>[for(c of'[](){}<>')x.split(c).length-1]

x=>[...'[](){}<>'].filter(c=>x.split(c).length>3)
x=>[for(c of'[](){}<>')if(x.split(c).length>3)c]

索引付け

配列の内包表記により、文字列/配列の現在のインデックスを取得するのが少し難しくなりますが、次のようにすることができます。

a.map((x,i)=>x+i).filter ((x,i)=>~i%2)
[for(x of(i=0,a))if(++i%2)x+i-1]

注意すべき主なことは、条件が満たされたときだけでなく、インデックスが毎回増加することを確認することです。

ジェネレーターの理解

ジェネレータ内包表記は、基本的に配列内包表記と同じ構文を持っています。括弧を括弧で置き換えるだけです:

x=>(for(c of x)if(c<'['&&c>'@')c.charCodeAt())

これにより、配列とほぼ同じように機能するジェネレーターが作成されますが、それは別の答えの話です。

概要

基本的に、理解度は通常よりも短いですが.map().filter()、それはすべて状況の詳細に帰着します。両方の方法で試して、どちらがうまく機能するかを確認するのが最善です。

PS理解に関する別のヒントや、この回答を改善する方法をお気軽にご提案ください!


ここではカップルより多くの文字を保存します範囲のためのトリックです:(x,y)=>[...Array(y-x)].map(a=>x++)
Mwr247

2
:あなたは、0からxまでの範囲を作るために、別の11のバイトを遮断することができますx=>[...Array(x).keys()]
Mwr247

そこの理解のための最後の1:n=>[for(x of Array(n).keys())if(/1/.test(x))x](7つのバイトが保存されます)
Mwr247

@ Mwr247実際、理解できる範囲は通常、他の優れたES6機能のように範囲が短くないことがわかります。代わりに文字列に関するセクションを追加し、範囲を処理できるようにします。
ETHproductions

配列内包表記が非推奨になり、javascriptのすべての最新バージョンから削除されたことは注目に値します。この件に関するMDNドキュメントを参照してください。
キーファーローク

13

ES6の関数式は矢印表記を使用しており、ES5バージョンと比較するとバイトを大幅に節約できます。

f=function(x,y){return x+y}
f=(x,y)=>x+y

関数にパラメーターが1つしかない場合は、括弧を省略して2バイトを節約できます。

f=x=>x+1

関数にパラメーターがない場合は、1バイトを保存するパラメーターがあるものとして宣言します。

f=()=>"something"
f=x=>"something"

注意:矢印関数は、とまったく同じではありませんfunction () {}。のルールthisは異なります(より良いIMO)。ドキュメントを見る


2
あなたはゴルフ-INGているときしかし、あなたは一般的に気にしないthisなど
オプティマイザ

1
一般的にはそうではありませんが、それは警告です。また、ラムダは、本番環境で関数ローカルのこのバインディングを必要としないことがより一般的です。
イサイアメドウズ

あなたはすべての引数を取りたい場合にも、あなたは「休息」引数の機能、例えばを使用することができ、f=(...x)=>x それを持っているでしょうf(1,2,3) => [1,2,3]
コナーオブライエン

1
ここでは、このサイトへの先端の特定です:あなたが形を取り機能と答えている場合(x,y)=>...、あなたがすることができカリー化してバイトを保存し、それを交換することによってx=>y=>...
Cyoce

12

使用してeval複数の文であり、aと矢印機能のためにreturn

私が偶然見つけたもっとばかげたトリックの1つ...

複数のステートメントとを必要とする単純な矢印関数を想像してくださいreturn

a=>{for(o="",i=0;i<a;i++)o+=i;return o}

単一のパラメータを受け入れる単純な関数a[0, a)、のすべての整数を反復処理しo、返される出力文字列の末尾に追加します。たとえば、これを4パラメータとして呼び出すと、が生成され0123ます。

この矢印関数は中括弧で囲む{}必要がありreturn o、最後にa が必要なことに注意してください。

この最初の試みは39バイトの重さです。

悪くはありませんが、を使用evalすることでこれを改善できます。

a=>eval('for(o="",i=0;i<a;i++)o+=i;o')

この関数は、コードをにラップevalして、eval評価の最後のステートメントを単純に作成することにより、中括弧とreturnステートメントを削除しましたo。これによりがeval返されo、関数oは単一のステートメントになったため、関数はを返します。

この改善された試行は38バイトで、オリジナルから1バイト節約されます

しかし、待ってください、まだあります!Evalステートメントは、最後に評価されたステートメントを返します。この場合、とo+=i評価されるoため、;o!は必要ありません。(ありがとう、edc65!)

a=>eval('for(o="",i=0;i<a;i++)o+=i')

この最後の試みの重さはわずか36バイトです -オリジナルより3バイト節約できます!


この手法は、矢印関数が値を返す必要があり、複数のステートメントを持っている必要がある一般的なケースに拡張できます(他の方法では組み合わせることができません)

b=>{statement1;statement2;return v}

になる

b=>eval('statement1;statement2;v')

バイトを保存します。

statement2評価される場合v、これは

b=>eval('statement1;statement2')

合計3バイトを節約します。


1
私は、匿名関数を書くだけでももっと短いかもしれないと
思う-Downgoat

@vihanそう、これらの関数は両方とも匿名にして、それぞれ2バイト節約できます。それでも、1バイトの節約は有効です。
-jrich

1
しかし、さらに良いことは、evalは評価された最後の式を返すため、必要ありません。;o試してみてくださいa=>eval('for(o="",i=0;i<a;i++)o+=i')
。– edc65

4
しかし、テンプレート文字列!
コナーオブライエン

1
@CᴏɴᴏʀO'Bʀɪᴇɴコンテキストとしてサンプル関数を使用して、テンプレート文字列がここでどのように機能するかを説明することに注意してください。
WallyWest

10

「\ n」よりもテンプレート文字列の改行を優先する

これにより、コード内の1行の改行文字でも成果が得られます。1つのユースケースは次のとおりです。

(16バイト)

array.join("\n")

(15バイト)

array.join(`
`)

更新:タグ付けされたテンプレート文字列のため、ブレースを残すこともできます(ありがとう、edc65!):

(13バイト)

array.join`
`

5
しかし、さらに良いことに、括弧を避けることができます。docs(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)を読んで理由を確認してください
edc65

ああ、そう。おかげで、私はそれを追加しました。
チル

9

配列の充填-静的な値と動的な範囲

私はもともとこれらを理解の下にコメントとして残していましたが、その投稿は主に理解に焦点を当てていたので、これを自分の場所にすると良いと思いました。

ES6では、ループを使用せずに配列に静的な値を入力することができました。

// ES5
function(x){for(i=0,a=[];i<x;i++)a[i]=0;return a}

// ES6
x=>Array(x).fill(0)

どちらも値0で埋められた長さxの配列を返します。

ただし、配列を動的な値(0 ... xの範囲など)で埋めたい場合、結果は少し長くなります(古い方法よりはまだ短くなります)。

// ES5
function(x){for(i=0,a=[];i<x;i++)a[i]=i;return a}

// ES6
x=>Array(x).fill().map((a,i)=>i)

どちらも値0で始まりx-1で終わる長さxの配列を返します。

.fill()配列が必要な理由は、配列を初期化するだけではマッピングできないためです。つまり、実行x=>Array(x).map((a,i)=>i)すると空の配列が返されます。次のようにスプレッド演算子を使用して、塗りつぶしの必要性を回避することもできます(したがって、さらに短くすることもできます)。

x=>[...Array(x)]

スプレッド演算子と.keys()関数を使用して、0 ... xの短い範囲を作成できるようになりました。

x=>[...Array(x).keys()]

x ... yからのカスタム範囲、または完全に特殊な範囲(偶数など)が必要な場合は、spread演算子を使用して、、またはuse .keys()を削除して使用できます。.map().filter()

// Custom range from x...y
(x,y)=>[...Array(y-x)].map(a=>x++)

// Even numbers (using map)
x=>[...Array(x/2)].map((a,i)=>i*2)

// Even numbers (using filter)
x=>[...Array(x).keys()].filter(a=>~a%2)

2番目の例の提案は次のとおりx=>Array(x).fill(i=0).map(a=>i++)です。また、0 in .fill(0)が必要かどうかもわかりません。なしで試しましたか?
ETHproductions

@ETHproductionsそうですね、マップ前の塗りつぶしには0は必要ないことを忘れていました。これにより、提案された文字よりも1文字短くなりますので、そのようにします。ありがとう!
Mwr247

また、最後の例でa=>a%2-1は、と同様に正常に機能しa=>a%2<1ます。
ETHproductions

1
私が学んだ新しいトリック:[...Array(x)]と同様に機能しArray(x).fill()、2バイト短くなります。x=>[...Array(x)].map((a,i)=>i)
ETHproductions

1
@yonatanmnとても素敵!コメントのみ1)1/4例は短く書き出され[0,0,0,0]、2)文字列化された関数は実装固有であるため、信頼できる長さを返しません(MapChromeでは32バイト、Firefoxでは36バイト)。
Mwr247

9

矢印関数で値を返す

単一のステートメントが矢印関数宣言の後に続く場合、そのステートメントの結果が返されることは一般的な知識です。

a=>{return a+3}
a=>a+3

-7バイト

したがって、可能であれば、複数のステートメントを1つに結合してください。これは、ステートメントを括弧で囲み、カンマで区切ることにより最も簡単に実行できます。

a=>{r=0;a.map(n=>r+=n);return r}
a=>(r=0,a.map(n=>r+=n),r)

-8バイト

ただし、ステートメントが2つしかない場合は、通常、それらを&&or と組み合わせることができます(より短い)||

a=>{r=0;a.map(n=>r+=n);return r}

// - Use && because map always returns an array (true)
// - declaration of r moved into unused map argument to make it only 2 statements
a=>a.map(n=>r+=n,r=0)&&r

-9バイト

最後に、マップ(または同様の)を使用していて、数値を返す必要があり、マップが数値を持つ1長の配列を決して返さないことを保証できる場合、次のようにして数値を返すことができます|

a=>{a=b=0;a.map(n=>(a+=n,b-=n));return a/b}

// - {} in map ensures it returns an array of undefined, so the | will make the returned
//   array cast from [ undefined, undefined, undefined ] to ",," to NaN to 0 and 0|n = n,
//   if the map returned [ 4 ] it would cast from [ 4 ] to "4" to 4 and make it 4|n
a=>a.map(n=>{a+=n,b-=n},a=b=0)|a/b

最後の例では、数値が常に整数であることを確認する必要もあります。
ETHproductions

8

ランダムなテンプレート文字列ハッキング

この関数は2つの文字列をリフリングします(つまりになり"abc","de"ます"adbec")。

f=(x,y)=>String.raw({raw:x},...y)

これxはがより長い場合にのみ機能することに注意してくださいy。どのように機能しますか?String.raw次のように、テンプレートタグとして設計されています。

String.raw`x: ${x}\ny: ${y}\nx + y: ${x + y}`

これは基本的にを呼び出しますがString.raw(["x: ", "\ny: ", "\nx + y: ", ""], x, y, x + y)、それほど単純ではありません。テンプレート配列には特別なrawプロパティもあります。これは基本的に配列のコピーですが、生の文字列を持ちます。String.raw(x, ...args)基本的にアイテムがなくなるx.raw[0] + args[0] + x.raw[1] + args[1] + x.raw[2] + ...まで戻りますx

これでString.raw、どのように機能するかがわかったので、それを有利に使用できます。

f=(x,y)=>String.raw({raw:x},...y)                   // f("abc", "de") => "adbec"
f=x=>String.raw({raw:x},...[...x].keys())           // f("abc") => "a0b1c"
f=(x,y)=>String.raw({raw:x},...[...x].fill(y))      // f("abc", " ") => "a b c"

もちろん、最後の1つについてf=(x,y)=>x.split``.join(y)は、かなり短くなりますが、アイデアは得られます。

ここもあれば動作する機能rifflingのカップルですxy同じ長さでは:

f=(x,y)=>String.raw({raw:x.match(/.?/g)},...y)
f=(x,y)=>String.raw({raw:x},...y)+y.slice(-1)  // Only works if x.length == y.length

String.raw MDNについて詳しく知ることができます。


7

再帰でゴルフする方法

再帰は、最速のオプションではありませんが、ほとんどの場合最短です。一般に、特に入力が数値または文字列の場合、ソリューションがチャレンジのより小さな部分のソリューションに単純化できる場合、再帰は最短です。例えば、場合f("abcd")により算出することができる"a"f("bcd")、それは再帰を使用するのがベストです。

例えば、階乗を取る:

n=>[...Array(n).keys()].reduce((x,y)=>x*++y,1)
n=>[...Array(n)].reduce((x,_,i)=>x*++i,1)
n=>[...Array(n)].reduce(x=>x*n--,1)
n=>{for(t=1;n;)t*=n--;return t}
n=>eval("for(t=1;n;)t*=n--")
f=n=>n?n*f(n-1):1

この例では、再帰は他のオプションより明らかに短いです。

文字コードの合計はどうですか:

s=>[...s].map(x=>t+=x.charCodeAt(),t=0)|t
s=>[...s].reduce((t,x)=>t+x.charCodeAt())
s=>[for(x of(t=0,s))t+=x.charCodeAt()]|t  // Firefox 30+ only
f=s=>s?s.charCodeAt()+f(s.slice(1)):0

これはややこしいですが、正しく実装すると、再帰によって4バイト以上節約されることがわかります.map

次に、さまざまなタイプの再帰を見てみましょう。

事前再帰

これは通常、最も短いタイプの再帰です。入力は、2つの部分に分割されるab、機能はして何かを計算aしてf(b)。階乗の例に戻ります:

f=n=>n?n*f(n-1):1

この場合には、aあるnはbであり、N-1 、および戻り値ですa*f(b)

重要な注意:すべての再帰関数には、入力が十分に小さいときに再帰を停止する方法が必要です。階乗関数では、これはで制御されますn? :1。つまり、入力が0の場合、再度呼び出すことなく1を返しfます。

再帰後

後再帰は前再帰に似ていますが、わずかに異なります。入力は、2つの部分に分割されるab、機能はして何かを計算しa、その後、呼び出しますf(b,a)。通常、2番目の引数にはデフォルト値(つまりf(a,b=1))があります。

最終結果で特別なことをする必要がある場合は、事前再帰が適しています。たとえば、数値に1を加えた階乗が必要な場合:

f=(n,p=1)=>n?f(n-1,n*p):p+1

ただし、それでも、post-は別の関数内で事前再帰を使用するよりも常に短いとは限りません。

n=>(f=n=>n?n*f(n-1):1)(n)+1

それで、それはいつ短くなりますか?この例では、再帰後では関数引数を括弧で囲む必要がありますが、再帰前では必要ありません。一般に、両方のソリューションで引数を括弧で囲む必要がある場合、後再帰は約2バイト短くなります。

n=>!(g=([x,...a])=>a[0]?x-a.pop()+g(a):0)(n)
f=([x,...a],n=0)=>a[0]?f(a,x-a.pop()+n):!n

この回答から取られたプログラム)

最短の解決策を見つける方法

通常、最短の方法を見つける唯一の方法は、それらすべてを試すことです。これも:

  • ループ
  • .map(文字列の場合、[...s].mapまたはs.replace;の場合、範囲作成できます
  • 配列内包表記
  • 事前再帰(これらのオプションの別の場合もあります)
  • 再帰後

そして、これらは最も一般的なソリューションです。最善の解決策は、これらの組み合わせ、またはまったく異なるものです。最短の解決策を見つける最良の方法は、すべて試すことです。


1
その値に対して+1であり、動物園用に別の+1を追加したい
edc65

7

より短い方法 .replace


ある正確な部分文字列のすべてのインスタンスを文字列内の別の部分文字列で置き換える場合、明白な方法は次のようになります。

f=s=>s.replace(/l/g,"y") // 24 bytes
f("Hello, World!")       // -> "Heyyo, Woryd!"

ただし、1バイト短くすることができます。

f=s=>s.split`l`.join`y`  // 23 bytes
f("Hello, World!")       // -> "Heyyo, Woryd!"

gフラグ以外の正規表現機能を使用する場合、これはもはや短くないことに注意してください。ただし、変数のすべてのインスタンスを置き換える場合、通常ははるかに短くなります。

f=(s,c)=>s.replace(RegExp(c,"g"),"") // 36 bytes
f=(s,c)=>s.split(c).join``           // 26 bytes
f("Hello, World!","l") // -> "Heo, Word!"

場合によっては、文字列内の各文字をマップして、それぞれを別のものに置き換えたいことがあります。私はしばしばこれをやっています:

f=s=>s.split``.map(x=>x+x).join`` // 33 bytes
f=s=>[...s].map(x=>x+x).join``    // 30 bytes
f("abc") // -> "aabbcc"

ただし、.replaceほとんどの場合は短くなります。

f=s=>s.replace(/./g,x=>x+x)  // 27 bytes
f=s=>s.replace(/./g,"$&$&")  // Also works in this particular case

これで、文字列内の各文字をマップしたいが、結果の文字列を気にしたくない場合.mapは、通常、次のものを取り除くことができるため、より良いです.join``

f=s=>s.replace(/./g,x=>t+=+x,t=0)&&t // 36 bytes
f=s=>[...s].map(x=>t+=+x,t=0)&&t     // 32 bytes
f("12345")  // -> 15

最後のケースでは、正規表現に一致する特定の文字(など/\w/g)のみに関心がある場合、このデモのように replaceを使用する方がはるかに優れています。
朝琴シエル

6

を使用したRegExリテラルの作成 eval

正規表現コンストラクターは、長い名前のために非常に大きくなる可能性があります。代わりに、evalとbackticksを使用してリテラルを記述します。

eval(`/<${i} [^>]+/g`)

変数iがに等しい場合foo、これは以下を生成します:

/<foo [^>]+/g

これは次と等しい:

new RegExp("<"+i+" [^>]+","g")

String.rawバックスラッシュを繰り返しエスケープする必要がないようにするためにも使用できます\

eval(String.raw`/\(?:\d{4})?\d{3}\d{3}\d{3}\d{3}\d{3}\d{3}\d{4}/g`)

これは出力します:

/(?:\d{4})?\d{3}\d{3}\d{3}/g

等しい

RegExp("\\(?:\\d{4})?\\d{3}\\d{3}\\d{3}\\d{3}\\d{3}\\d{3}\\d{4}","g")

覚えておいてください!

String.raw 多くのバイトを使用します。 少なくとも 9つのバックスラッシュ、String.raw長くなります。


newそこにある必要はないので、コンストラクターの使用は実際には2番目の例
オプティマイザー

5

.forEachforループ

常に.mapforループを使用してください。簡単ですぐに節約できます。


a.map(f)
for(x of a)f(x);
for(i=0;i<a.length;)f(a[i++]);
  • 合計8バイトオリジナルの
  • for-of(50%に対して8バイト節約削減)
  • 22バイトの節約とCスタイルのforループ(73%の削減)

a.map(x=>f(x,0))
for(x of a)f(x,0);
for(i=0;i<a.length;)f(a[i++],0);
  • 合計16バイトオリジナルの
  • for-ofに対して2バイト節約11%削減)
  • 16バイトの節約とCスタイルのforループ(50%削減)

a.map((x,i)=>f(x,i,0))
for(i in a)f(a[i],i,0);
for(i=0;i<a.length;)f(a[i],i++,0);
  • 合計22バイトオリジナルの
  • for-inに対して1バイト節約4%削減)
  • Cスタイルのforループに対して11バイト節約33%削減)

a.map(x=>f(x)&g(x))
for(x of a)f(x),g(x);
for(i=0;i<a.length;)f(x=a[i++]),g(x);
  • オリジナルの合計19バイト
  • for-ofに対して2バイト節約10%削減)
  • Cスタイルのforループに対して18バイト節約49%削減)

5

再帰で初期化されていないカウンターを使用する

:厳密に言えば、これはES6に固有のものではありません。ただし、矢印関数は簡潔であるため、ES6で再帰を使用および悪用する方が理にかなっています。


kゼロに初期設定され、反復ごとに増分されるカウンターを使用する再帰関数に遭遇するのはかなり一般的です。

f = (…, k=0) => [do a recursive call with f(…, k+1)]

特定の状況では、このようなカウンターの初期化を省略して、次のものに置き換えることk+1ができ-~kます。

f = (…, k) => [do a recursive call with f(…, -~k)]

通常、このトリック 2バイト節約します

なぜ、いつ機能するのですか?

それを可能にする公式は~undefined === -1です。したがって、最初の反復で-~kはに評価され1ます。次の反復で-~kは、少なくとも範囲[0…2 31の整数の-(-k-1)場合k+1、本質的にwhich equalsと等しい -1]のです。

ただしk = undefined、最初の反復で関数の動作が中断されないようにする必要があります。特に、算術演算の大部分はを伴うundefinedことに注意してくださいNaN

例1

正の整数を指定するとn、この関数はk分割しない最小の整数を探しますn

f=(n,k=0)=>n%k?k:f(n,k+1)   // 25 bytes

次のように短縮できます。

f=(n,k)=>n%k?k:f(n,-~k)     // 23 bytes

これn % undefinedNaNであるため機能します。これが最初の反復で期待される結果です。

[元の回答へのリンク]

例2

正の整数を指定するとn、この関数は次のpような整数を探します(3**p) - 1 == n

f=(n,p=0,k=1)=>n<k?n>k-2&&p:f(n,p+1,k*3)  // 40 bytes

次のように短縮できます。

f=(n,p,k=1)=>n<k?n>k-2&&p:f(n,-~p,k*3)    // 38 bytes

これpは、最初の反復ではまったく使用されない(n<k偽である)ために機能します。

[元の回答へのリンク]


5

ES6関数

数学

Math.cbrt(x)よりも文字を保存しますMath.pow(x,1/3)

Math.cbrt(x)
Math.pow(x,1/3)

3文字保存

Math.hypot(...args)引数の平方和の平方根が必要な場合に便利です。そのためにES5コードを作成するのは、ビルトインを使用するよりもはるかに困難です。

この関数は短いMath.trunc(x)ので、役に立たないでしょうx|0。(Mwr247に感謝!)

ES5では多くのコードを必要とする多くのプロパティがありますが、ES6ではより簡単です。

  • Math.acoshasinhatanhcoshsinhtanh。三角関数の双曲線等価を計算します。
  • Math.clz32。ES5でできるかもしれませんが、今は簡単です。数値の32ビット表現の先行ゼロをカウントします。

そこより多くしているので、私はちょうどいくつかをリストアップするつもりです:
Math.signMath.froundMath.imulMath.log10Math.log2Math.log1p


Math.trunc(x)の4倍の長さですx|0
Mwr247

@ mwr247:OK、更新します。
ev3commander

:ここで私は、これらの機能のカップルのための知っている最短ES5同等だMath.hypot(a,b) => Math.sqrt(a*a+b*b)、(より多くの引数を指定しても、長くなる3バイト以上)Math.sign(a) => (a>0)-(a<0);(と動作しないことが1バイト短いが、いくつかのケースでは括弧を取り巻くニーズNaN
ETHproductions

@ETHproductions(es5の回避策)hypotの引数配列が必要です。そして、Math.signの回避策が-0で機能することを確信していますか?(-0を返す必要があります)
ev3commander

1
@ ev3commanderこれらは、それぞれのES6の同等物のインライン置換としての意味であるため、使用の99%に縮小されます。これらの関数を完全に再作成するには、さらに多くのコードが必要になります。また、(知る限り)-0を手動で指定しない限り、-0を取得する方法がなく、code-golf内では実質的に使用しないため、-0に特別なケースが必要な理由はありません。しかし、それらを指摘してくれてありがとう。
ETHproductions

5

小さい定数範囲の最適化 map()

状況

ES6から、範囲map()ではなくforループの代わりにメソッドを使用(および悪用)することがかなり一般的になりました[0 ..N1]、したがって、答え全体を機能的なスタイルで書くことができます:

for(i = 0; i < 10; i++) {
  do_something_with(i);
}

次のいずれかに置き換えることができます。

[...Array(10).keys()].map(i => do_something_with(i))

またはより一般的に:

[...Array(10)].map((_, i) => do_something_with(i))

ただし、次の場合に使用することArray(N)はめったに最適ではありません。N は小さな定数です。

範囲の最適化 [0 ..N1]、カウンター付き

以下は、カウンターが コールバック内で使用されます:

N           | Method                               | Example                         | Length
------------+--------------------------------------+---------------------------------+-------
N ≤ 6       | use a raw array of integers          | [0,1,2,3].map(i=>F(i))          | 2N+10
N = 7       | use either a raw array of integers   | [0,1,2,3,4,5,6].map(i=>F(i))    | 24
            | or a string if your code can operate | [...'0123456'].map(i=>F(i))     | 23
            | with characters rather than integers |                                 |
8 ≤ N ≤ 9   | use scientific notation 1e[N-1]      | [...1e7+''].map((_,i)=>F(i))    | 24
N = 10      | use scientific notation 1e9          | [...1e9+''].map((_,i)=>F(i))    | 24
            | or the ES7 expression 2**29+'4' if   | [...2**29+'4'].map(i=>F(i))     | 23
            | the order doesn't matter and your    |                                 |
            | code can operate with characters     |  (order: 5,3,6,8,7,0,9,1,2,4)   |
            | rather than integers                 |                                 |
11 ≤ N ≤ 17 | use scientific notation 1e[N-1]      | [...1e12+''].map((_,i)=>F(i))   | 25
N = 18      | use the fraction 1/3                 | [...1/3+''].map((_,i)=>F(i))    | 24
N = 19      | use the fraction 1/6                 | [...1/6+''].map((_,i)=>F(i))    | 24
20 ≤ N ≤ 21 | use scientific notation 1e[N-1]      | [...1e20+''].map((_,i)=>F(i))   | 25
N = 22      | use scientific notation -1e20        | [...-1e20+''].map((_,i)=>F(i))  | 26
23 ≤ N ≤ 99 | use Array(N)                         | [...Array(23)].map((_,i)=>F(i)) | 27

注意:コールバックコードの長さはF(i)カウントされません。

範囲の最適化 [1..9]、カウンター付き

範囲を反復処理する場合 [1..9] 順序は関係ありませんが、次のES7式を使用できます(コードが整数ではなく文字で動作できる場合)。

[...17**6+'8'].map(i=>F(i))  // order: 2,4,1,3,7,5,6,9,8; length: 23

カウンターなしの最適化

繰り返す必要がある場合は、次のメソッドを使用できます N カウンターを使用しない場合:

N           | Method                               | Example                         | Length
------------+--------------------------------------+---------------------------------+-------
N ≤ 5       | use a raw array of integers          | [0,0,0,0].map(_=>F())           | 2N+10
6 ≤ N ≤ 10  | use scientific notation 1e[N-1]      | [...1e7+''].map(_=>F())         | 20
11 ≤ N ≤ 17 | use scientific notation 1e[N-1]      | [...1e12+''].map(_=>F())        | 21
N = 18      | use the fraction 1/3                 | [...1/3+''].map(_=>F())         | 20
N = 19      | use the fraction 1/6                 | [...1/6+''].map(_=>F())         | 20
20 ≤ N ≤ 21 | use scientific notation 1e[N-1]      | [...1e20+''].map(_=>F())        | 21
N = 22      | use scientific notation -1e20        | [...-1e20+''].map(_=>F())       | 22
23 ≤ N ≤ 99 | use Array(N)                         | [...Array(23)].map(_=>F())      | 23

注意:コールバックコードの長さはF()カウントされません。


するべきでは2**26ない2**29
シャギー

@Shaggy Heck。良いキャッチ!
アーナウルド

自分で編集したくありませんでした :D
シャギー

使用して.keys()、あなたがラムダを必要としない:[...Array(10).keys()].map(do_something_with)
長期ラズリ

@ long-lazuliラムダが不要で、範囲が必要な場合は、おそらくマップも必要ありません
...-Arnauld

4

割り当ての破壊

ES6では、割り当てを分解するための新しい構文が導入されています。つまり、値を断片に分割し、各断片を異なる変数に割り当てます。以下に例を示します。

文字列と配列

a=s[0];b=s[1];       // 14 bytes
[a,b]=s;             //  8 bytes

a=s[0];s=s.slice(1); // 20 bytes
a=s.shift();         // 12 bytes, only works if s is an array
[a,...s]=s;          // 11 bytes, converts s to an array

オブジェクト

a=o.asdf;b=o.bye;c=o.length; // 28 bytes
{asdf:a,bye:b,length:c}=o;   // 26 bytes

a=o.a;b=o.b;c=o.c; // 18 bytes
{a,b,c}=o;         // 10 bytes

これらの割り当ては、関数パラメーターでも使用できます。

f=a=>a[0]+a[1]+a[2]
f=([a,b,c])=>a+b+c

f=b=>b[1]?b[0]+f(b.slice(1)):b[0]*2
f=b=>b[1]?b.shift()+f(b):b[0]*2
f=([a,...b])=>b[0]?a+f(b):a*2

4

回避する別の方法 return

複数のステートメントとreturn使用する矢印関数にはevalを使用する必要があることを知っています。まれなケースでは、内部サブ関数を使用してさらに節約できます。

私が言うのは珍しいので、

  1. 返される結果は、ループで評価された最後の式であってはなりません

  2. ループの前に(少なくとも)2つの異なる初期化が必要です。

この場合、戻り値なしで内部サブ関数を使用し、初期値の1つをパラメーターとして渡すことができます。

a〜bの範囲の値のexp関数の合計の逆数を求めます。

長い道のり-55バイト

(a,b)=>{for(r=0,i=a;i<=b;i++)r+=Math.exp(i);return 1/r}

評価付き-54バイト

(a,b)=>eval("for(r=0,i=a;i<=b;i++)r+=Math.exp(i);1/r")

内部機能付き-53バイト

(a,b)=>(i=>{for(r=0;i<=b;i++)r+=Math.exp(i)})(a)||1/r

範囲の下限の要件なしで、aiとrの初期化をマージでき、evalバージョンはより短いことに注意してください。


サンプルでは、​​保存する必要はありませんa
-l4m2

@ l4m2私はあなたのポイントを得ることができません、助けてください
...-edc65

(i,b)=>{for(r=0;i<=b;i++)r+=Math.exp(i);return 1/r}
l4m2

@右ええとl4m2、 return a/rより良い例だろう
edc65

1
evalは依然として優れて(a,b)=>1/eval("for(r=0,i=a;i<=b;i++)r+=Math.exp(i)")おり、この場合(i,b)=>1/eval("for(r=0;i<=b;)r+=Math.exp(i++)")
JayXon

4

二項関数および再帰関数にカリー化構文を使用する

二項関数

関数がデフォルト値なしでちょうど2つの引数を取る場合は常に、カリー化構文を使用すると1バイト節約されます。

f =
(a,b)=>a+b  // 10 bytes

と呼ばれる f(a,b)

f =
a=>b=>a+b   // 9 bytes

と呼ばれる f(a)(b)

Metaのこの投稿では、この構文の妥当性を確認しています。

再帰関数

カリー化構文を使用すると、再帰関数が複数の引数をとるが、各反復の間にそれらの一部のみを更新する必要がある場合にも、いくつかのバイトを節約できます。

次の関数は、範囲内のすべての整数の合計を計算します[a,b]

f=(a,b)=>a>b?0:b+f(a,b-1)   // 25 bytes

aプロセス全体を通して変更されないため、次を使用して3バイトを節約できます。

f =                         // no need to include this assignment in the answer anymore
a=>F=b=>a>b?0:b+F(b-1)      // 22 bytes

:コメントでNeilが気付いたように、引数が再帰関数に明示的に渡されないという事実は、それが不変であると見なされるべきであることを意味しません。必要に応じて、a関数コード内でa++a--または同様の構文を使用して変更できます。


最後の例は、と書くことができ、各再帰呼び出しをa=>F=b=>a>b?0:a+++F(b)変更aします。これはその場合には役に立ちませんが、引数が多い場合にバイトを節約するかもしれません。
ニール

ねえ、私はちょうどこのためのヒントを書くことを考えていた:
ETHproductions

4

素数テスト関数

次の28バイト関数はtrue、素数およびfalse非素数を返します。

f=(n,x=n)=>n%--x?f(n,x):x==1

これは、他のことを計算するために簡単に変更できます。たとえば、次の39バイトの関数は、ある数以下の素数をカウントします。

f=(n,x=n)=>n?n%--x?f(n,x):!--x+f(n-1):0

既にn素数性をチェックしたい変数がある場合、素数関数はかなり単純化できます:

(f=x=>n%--x?f(x):x==1)(n)

使い方

f = (         // Define a function f with these arguments:
  n,          //   n, the number to test;
  x = n       //   x, with a default value of n, the number to check for divisibility by.
) =>
  n % --x ?   //   If n is not divisible by x - 1,
  f(n, x)     //     return the result of f(n, x - 1).
              //   This loops down through all numbers between n and 0,
              //     stopping when it finds a number that divides n.
  : x == 1    //   Return x == 1; for primes only, 1 is the smallest number
              //     less than n that divides n.
              //   For 1, x == 0; for 0, x == -1.

注:12345などの十分に大きな入力で呼び出された場合、これは「too much recursion」エラーで失敗します。ループでこれを回避できます。

f=n=>eval('for(x=n;n%--x;);x==1')

1
ただし、入力が12345
edc65

x==1おそらくx<2節約になります。
電卓

@CalculatorFelineおかげで、しかし、それはのために失敗した10(あるためxだろう0か、-1それぞれ、)
ETHproductions

特定の場合に役立つ可能性があります。また、!~-x-0バイトの場合。
電卓

3

Array#concat() スプレッド演算子

これは状況に大きく依存します。


複数の配列を組み合わせます。

クローンを作成しない限り、concat関数を優先します。

0バイト保存

a.concat(b)
[...a,...b]

無駄な3バイト

a.concat(b,c)
[...a,...b,...c]

3バイト保存

a.concat()
[...a]

6バイト保存

// Concatenate array of arrays
[].concat.apply([],l)
[].concat(...l)

に既存の配列を使用することをお勧めしArray#concat()ます。

簡単な4バイトの節約

[].concat(a,b)
a.concat(b)

3

中間結果を返す

コンマ演算子を使用すると、最後の値を返す一連の式を実行できることがわかっています。しかし、リテラル配列構文を乱用すると、中間値を返すことができます。たとえば、.map()で役立ちます。

// capitalize words
// f is a flag indicating if prev char is space
[...x].map(c=>(f?c=c.toUpperCase():0,f=c<'!',c),f=1).join('')

// shortened to ...
[...x].map(c=>[f?c.toUpperCase():c,f=c<'!'][0],f=1).join('')

3
もちろん、それ.join('')は次のようになります.join``
16年

3

関数パラメーターのデフォルトを設定する

($,a,b,_)=>_!=undefined?'asdf':_ // before
($,a,b,_)=>_!=[]._?'asdf':_ // before, but a bit golfed
($,a,b,_='asdf')=>_ // after

これは本当に便利です...

ただし、_=>_||'asdf'1つの(有用な)引数のみを関数に渡す場合は、次のようなものが短いことを必ず理解してください。


1
私は、ORを使用することに注意したい_=>_||'asdf'ほとんどの場合、通常は短いです
Downgoat

@Downgoat (空の文字列)の"asdf"入力に対して返されることに注意してください""
ETHproductions

2
引数がundefined明示的に渡された場合でも、引数がの場合は常にデフォルトが評価されることに注意してください。たとえば、は[...Array(n)].map((a,b,c)=>b)常にに渡さundefinedれるaため、デフォルト値を提供できます(ただし、ではありませんb)。
ニール

3

つかいます eval矢印関数に中括弧の代わりにする

矢印機能は素晴らしいです。それらはの形式を取りx=>y、ここでxは引数でyあり、戻り値です。ただし、などの制御構造を使用する必要がある場合は、while中括弧などを挿入する必要があります=>{while(){};return}。ただし、これを回避できます。幸いなことに、このeval関数は文字列を受け取り、その文字列をJSコードとして評価し、最後に評価された式返します。たとえば、次の2つを比較します。

x=>{while(foo){bar};return baz} // before
x=>eval('while(foo){bar};baz')  // after
//                            ^

この概念の拡張を使用して、コードをさらに短縮できます。の観点からeval、制御構造は最後に評価された式も返します。例えば:

x=>{while(foo)bar++;return bar} // before
x=>eval('while(foo)++bar')      // after
//                        ^^^^^

3

ES6でのゴルフの論理操作

「GLOE(S6)」

一般的なロジック

ステートメントsとを構築したとしtます。次の置換のいずれかを使用できるかどうかを確認します。

Traditional conjuction: s&&t
Equivalent conjuction: s*t OR s&t

Traditional disjunction: s||t
Equivalent disjunction: s+t OR s|t

(順序が間違っている場合、これらは機能しない可能性があります。つまり+、および*より優先順位が低く||なり&&ます。)

また、ここにいくつかの便利な論理式があります:

  • どちらかsまたはt真/ XORです。s^t
  • sそしてt、同じ真理値です:!s^tまたはs==t

配列ロジック

a条件を満たすすべてのメンバーp

a.every(p)                             // 10 bytes (11 bytes saved)
a.map(x=>c&=p(x),c=1)                  // 21 bytes (16 bytes saved)
for(i=0,c=1;i<a.length;c&=p(a[i++]));  // 37 bytes (hideously long)

の少なくとも1つのメンバーがa条件を満たしますp

a.some(p)                            // 9  bytes (13 bytes saved)
a.map(x=>c|=p(x),c=0)                // 21 bytes (14 bytes saved)
for(i=c=0;i<a.length;c|=p(a[i++]));  // 35 bytes (just please no)

次のa条件を満たすメンバーはいませんp!a.some(p)

要素eは配列に存在しaます:

a.includes(e)                        // 13 bytes, standard built-in
~a.indexOf(e)                        // 13 bytes, "traditional" method
a.find(x=>e==x)                      // 15 bytes, find (ES6)
a.some(x=>x==e)                      // 15 bytes, some (ES5)
(a+"").search(e)                     // 16 bytes, buggy
a.filter(t=>t==e).length             // 24 bytes, no reason to use this
for(i=c=0;i<a.length;c+=e==a[i++]);  // 35 bytes, super-traditional

要素eが配列に存在しませa

!a.includes(e)
!~a.indexOf(e)
a.every(t=>t!=e)
!a.filter(t=>t==e).length
for(i=0,c=1;i<a.length;c*=e!=a[i++]);

私は一般的に使用&&し、||などx?y:xx?x:yそれぞれ。しかし、これがよりロジックベースのプログラムでどのように役立つかがわかります。問題の1つ+は、たとえば3-3が両方とも真実であるということですが、そうで3+-3はありません。
ETHproductions

@ETHproductionsああ、あなたは正しい。それはエッジケースです。-場合も動作する可能性がありs != tます。
コナーオブライエン

a.filter(t=>t==e).length==a.length間違っています。それはする必要があります!a.filter(t=>t==e).length
ETHproductions

@ETHproductionsはあなたです!
コナーオブライエン

3

繰り返される関数呼び出しを短縮する

キャンバスの操作など、長い名前の関数を繰り返し呼び出した場合:

c.lineTo(0,100);c.lineTo(100,100);c.lineTo(100,0);c.lineto(0,0);c.stroke()

これを短縮する従来の方法は、関数名をエイリアスすることです。

c[l='lineTo'](0,100);c[l](100,100);c[l](100,0);c[l](0,0);c.stroke()

十分な呼び出しがある場合、より良い方法は、あなたのために仕事をする関数を作成することです:

l=(x,y)=>c.lineTo(x,y);l(0,100);l(100,100);l(100,0);l(0,0);c.stroke()

ほとんどの関数呼び出しがチェーン化されている場合、関数がそれ自体を返すようにすることができます。これにより、連続する呼び出しごとに2バイトを削減できます。

l=(x,y)=>c.lineTo(x,y)||l;l(0,100)(100,100)(100,0)(0,0);c.stroke()

使用例:12


1
あなたが短縮することができますバインド演算子(l=::c.lineTo)(0,100)(100,100)(100,0)(0,0);c.stroke()
Downgoat

@Downgoatありがとう、どのブラウザがそれをサポートしていますか?(また、私が見てきたことから、2番目の呼び出しでエラーが発生します。c.lineTo自然にそれ自体が返されないためです)
ETHproductions

ES7の機能であるため、babel
でこする必要があります-Downgoat

3

バインド演算子 ::

バインド演算子を使用して、繰り返される関数のバイト数を短縮できます。

(x='abc'.search(a))+x.search(b) // Before
(x=::'abc'.search)(a)+x(b)      // 5 bytes saved

さらに、別のthis例で関数を使用する場合:

s[r='replace'](/a/g,'b')+s[r](/c/g,'d') // Before
(r=s.replace)(/a/g,'b')+s::r(/c/g,'d')  // 1 byte saved

3

大量のデータを保存する際のコンマの回避

配列に格納する必要のあるデータ(インデックス、文字など)がたくさんある場合は、すべてのコンマを残しておく方が良いかもしれません。これは、すべてのデータの文字列の長さが同じ場合に最適に機能し、明らかに1が最適です。

43バイト(ベースライン)

a=[[3,7,6,1,8,9,4,5,2],[5,4,3,2,7,6,5,4,3]]

34バイト(コンマなし)

a=[[..."376189452"],[..."543276543"]]

配列アクセス変更する場合は、これをさらに減らして、同じ値を次のように保存します。

27バイト(同じデータ、配列アクセスのみを変更)

a=[..."376189452543276543"]

最後のブロックのみが強調表示されるのはなぜですか?
電卓

@CalculatorFelineありがとう、修正。
チル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.