この記事を読んでJavaScriptにもflatMapが欲しくなったので作ってみた。
まずは普通の関数
func_flatMap.js
function flatMap(xs, f) {
return xs.reduce(function (ys, x) {
return ys.concat(f(x));
}, []);
}
//=> [4, 12, 20, 28, 36]
console.log(flatMap([1,2,3,4,5,6,7,8,9,10], function (x) {
return x % 2 === 1 ? [x << 2] : [];
}));
ネストがアレです。
次はArray.prototypeの拡張
prototype_flatMap.js
Object.defineProperty(Array.prototype, 'flatMap', {
value: function (f, self) {
self = self || this;
return this.reduce(function (ys, x) {
return ys.concat(f.call(self, x));
}, []);
},
enumerable: false,
});
//=> [4, 12, 20, 28, 36]
console.log([1,2,3,4,5,6,7,8,9,10].flatMap(function (x) {
return x % 2 === 1 ? [x << 2] : [];
}));
列挙しないようにしてますけど、他のライブラリと競合すう可能性ありそうだな……。
最後に、underscore.jsでやってみました。
js;underscore_flatMap.js
var
_ = require('underscore');
var
flatMap = _.flatMap = _.concatMap = function (xs, f, self) {;
return _.reduce(xs, function (ys, x) {
return ys.concat(f.call(self, x));
}, []);
};
_.each(['flatMap', 'concatMap'], function (name) {
_.prototype[name] = function (f, self) {
return _(flatMap(this.value(), f, self));
};
});
//さっきよりシンプルになったように見えるのは_.rangeのおかげ?
console.log(_.flatMap(_.range(1, 11), function (x) {
return x % 2 === 1 ? [x << 2] : [];
}));
//こういう風にも書ける
console.log(_(_.range(1, 11)).flatMap(function (x) {
return x % 2 === 1 ? [x << 2] : [];
}).value());
というか何でunderscore.jsにはflatMapが無いのでしょう? 解せません。
あと、ここに載せたコードは煮るなり焼くなり好きにしてやって下さい。