はじめに
- JavaScriptでgroup_byを使って、手続き型のアルゴリズムをコレクション操作の関数型アルゴリズムにリファクタリング
座標点とポリラインの入力でまとめて処理
入力データは点の集まりだが、途中に名前がついてない点は直前の点に付随してポリラインを構成したい。
配列添字3番目のデータは、直前の2番目のデータと合わせて配列にする。その他の点は要素数1の配列で良い、とする。
手続型
this.sequences = list.inject([], (sequences, src, row_i) => {
if (row_i < (this.isIgnore ? this.ignoreLines : 0))
return sequences;
if (
this.thead.every((attr, i) =>
attr == 'ignore' ? true : src[i] == null
)
)
return sequences; // 空行はスキップ
const point = this.thead.inject({}, (p, attr, i) => {
if (attr == 'ignore') return p;
return p._assign(attr, src[i]);
}); //データ構造をオブジェクトに変える
if (sequences.last() == null) { //結果が何もなければ点として積む
sequences.push([point]);
} else if ( // 名前がないか、直前の点と同じなら、積んだ配列の最後に加える
point.name == '' ||
point.name == sequences.last()[0].name
) {
sequences.last().push(point);
} else { //新たな点として積む
sequences.push([point]);
}
return sequences;
});
group_byを使って関数型にする
const sequences = list.filter((sequence, i) => {
return (
i >= (this.isIgnore ? this.ignoreLines : 0) &&
this.thead.some((attr, j) =>
attr == 'ignore' ? false : sequence[j] != null
)
);
}); // まず必要なものだけ残す
const sequencesList = sequences
.map((sequence) => {
return this.thead.inject({}, (p, attr, i) => {
if (attr == 'ignore') return p;
return p._assign(attr, sequence[i]);
});
})// オブジェクトに変換する
.group_by((point, i, self) => {
if (point.name != '')
return point.name; //nameプロパティの値でグループ化
const p = self.slice(0, i) // nameが''なら、元配列の自己位置から
.findLast(({ name }) => name != ''); //逆向きに探索
return p.name; //結果の値でグループ化
});
なお、group_byとは
function group_by(cond){
return Object.values(this.reduce(function (ret, e, i, self) {
var val = cond(e, i, self);
if (ret[val] == null) //与えた評価関数の値をキーとする配列を作る
ret[val] = [e];
else
ret[val].push(e); // キーが存在すれば配列に積む
return ret;
}, {})
) // キーは捨てて、配列を値とする配列を戻り値とする
}