ワンライナーで行こう!

ワンライナーとは

はてなキーワードによると、

「ワンライナー」とは、たった1行だけのプログラムです。PerlやRubyを使うと、1行だけでもかなりの仕事ができます。 プログラムを書きたいが、エディタを起動するほどの手間はかけたくない、というときに威力を発揮します。達人ともなると、ちょっとした文字置換や計算をするワンライナーを、即興で作って使い捨てることもあります。PerlやRubyは、ワンライナーを書くために役立つオプションを豊富に持っています。

Javascriptでも、ES2015以降、アロー演算子や、Array.prototype.filterやArray.prototype.map等の関数でワンライナーが作りやすくなりました。配列操作系を中心に、便利なワンライナー集を作ってみました!

※ネタが思い付き次第順次追加していきたいと思います。「もっと短くできる!」「イクナイ」等のご指摘や、他のワンライナーネタがありましたら、コメント欄にお願いします。

startからendまでの連続した数値配列を生成する

start=1, end=10の配列(公差1の等差数列)を生成

var array = Array(end-start+1).fill().map((e,i) => start+i);
//または
var array = Array.apply(0,new Array(end-start+1)).map((e,i) => start+i);

//console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

特定の値の要素を入れ替える

before = 10 から after = 1 へ置換

array = array.map(e => e===before ? after : e);

//console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 1 ]

特定の値の要素を削除する

target = 9 を削除

array = array.filter(e => e!==target);

//console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8, 1 ]

配列を降順に並び替える

昇順の場合は(a,b)=>a-b。破壊的メソッドのため、=演算子での上書き不要。

array.sort((a,b)=>b-a);

//console.log(array)--> [ 8, 7, 6, 5, 4, 3, 2, 1, 1 ]

配列を逆順に並び替える

Array.prototype.reverse()そのまま。破壊的メソッドのため、=演算子での上書き不要。

array.reverse();

//console.log(array) --> [ 1, 1, 2, 3, 4, 5, 6, 7, 8 ]

配列から重複する値を削除する

array = array.filter((e,i,s) => i===s.indexOf(e));

//console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8 ]

2つの配列を結合する

array = array.concat(array);
//または
array = [...array,...array];
// console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 ]

配列から重複する値のみ残す

array = array.filter((e,i,s) => s.indexOf(e)!==s.lastIndexOf(e));

// console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 ]

配列から重複する値のみ残した後、重複削除

array = array.filter((e,i,s) => i!==s.indexOf(e));

// console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8 ]

配列の中身を結合した文字列を作る

var string = array.join().replace(/,/g,"");

// console.log(string) --> 12345678

数値文字列を分割して数値配列にする

map(e => +e)で数値形式の文字列から数値に変換するのがミソ。

array = string.split('').map(e => +e);
//または
array = Array.from(string).map(e => +e);

// console.log(array) --> [ 1, 2, 3, 4, 5, 6, 7, 8 ]

配列中の数値の合計値を得る

var sum = array.reduce((a,b) => a+b);

// console.log(sum) --> 36

配列中の数値の最大値を得る

var max = array.reduce((a,b) => a<b ? b : a);
//または
var max = Math.max.apply(null, array);
//または
var max = Math.max(...array);
// console.log(max) --> 8

隣り合うN個の要素をまとめた配列の配列を作る(N=3)

filter(e => e.length===3)で、要素数が3に満たない配列[7,8]を落としている

var v = array.map((e,i,s) => i%3===0 ? s.slice(i,i+3) : null).filter(e => e!==null && e.length===3);

// console.log(v) --> [[ 1, 2, 3 ], [ 4, 5, 6 ] ]

3次元ベクトルの内積

上で作成した2つのベクトル v=[[ 1, 2, 3 ], [ 4, 5, 6 ] ]を使う

var ip = v[0].map((e,i) => v[0][i]*v[1][i]).reduce((a,b) => a+b);

// console.log(ip) --> 32

3次元ベクトルの外積

内積と同様、v=[[ 1, 2, 3 ], [ 4, 5, 6 ] ]を使う

var op = v[0].map((e,i) => v[0][(i+1)%3]*v[1][(i+2)%3]-v[0][(i+2)%3]*v[1][(i+1)%3]);

// console.log(op) --> [ -3, 6, -3 ]

隣り合う2要素をまとめた配列の配列を作る(N=2)

N=3の場合をN=2にしただけ

var m = array.map((e,i,s) => i%2===0 ? s.slice(i,i+2) : null).filter(e => e!==null && e.length===2);

// console.log(m) --> [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]

マークル木演算

だいぶ苦しくなってきた。ツーライナーに見えるのは気のせいです…
ブランチのペアは上記の m= [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]を使用。ここでは任意のハッシュ関数をhash()としています。

var i=~~Math.pow(m.length,1/2);while(i>0){m=m.map((e,i,s)=>i%2===0?[hash(e),hash(s[i+1])]:null).filter(e=>e!==null); i=+(i-1);}

マークルツリーアルゴリズムについての解説はこちらを参照しました。
本来、ブランチは文字列で、ループの前に1度ハッシュ関数を通す等の前処理が必要ですが、とりあえず主要部分のみ。

hash()を単なる2要素の足し算にして検算した結果↓(実際に使う場合はSHA256等のハッシュ関数に置き換える)

const hash = (a) => a[0]+a[1]; 

// console.log(...m) --> [ 10, 26 ]  //スプレッド演算子で2重括弧状態を解除

Leave a Reply

Your email address will not be published. Required fields are marked *