flatMap
コレクションで非常に便利ですが、javascriptはArray.prototype.map
。を持っている間はそれを提供しません。どうして?
手動でflatMap
定義せずに、簡単かつ効率的な方法でJavaScriptでエミュレートする方法はありますflatMap
か?
flatMap
コレクションで非常に便利ですが、javascriptはArray.prototype.map
。を持っている間はそれを提供しません。どうして?
手動でflatMap
定義せずに、簡単かつ効率的な方法でJavaScriptでエミュレートする方法はありますflatMap
か?
arr.map(...).reduce(...)
)。
.map
ます。
回答:
更新: Array.prototype.flatMap
ES2019になりました
多くの環境で広くサポートされています。以下のスニペットを使用して、ブラウザで機能するかどうかを確認してください-
const data =
[ 1, 2, 3, 4 ]
console.log(data.flatMap(x => Array(x).fill(x)))
// [ 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 ]
「JavaScriptにArray.prototype.flatMapがないのはなぜですか?」
プログラミングは魔法ではなく、すべての言語が他のすべての言語が持っている機能/プリミティブを持っているわけではないからです。重要なのは、JavaScriptがあなた自身でそれを定義する能力を与えることです-
const concat = (x,y) =>
x.concat(y)
const flatMap = (f,xs) =>
xs.map(f).reduce(concat, [])
const xs = [1,2,3]
console.log(flatMap(x => [x-1, x, x+1], xs))
または、2つのループを1つに折りたたむ書き直し-
const flatMap = (f, xs) =>
xs.reduce((r, x) => r.concat(f(x)), [])
const xs = [1,2,3]
console.log(flatMap(x => [x-1, x, x+1], xs))
あなたがそれを拡張したいのならArray.prototype
、何もあなたを止めていません-
if (!Array.prototype.flatMap) {
function flatMap (f, ctx) {
return this.reduce
( (r, x, i, a) =>
r.concat(f.call(ctx, x, i, a))
, []
)
}
Array.prototype.flatMap = flatMap
}
const ranks =
[ 'J', 'Q', 'K', 'A' ]
const suits =
[ '♡', '♢', '♤', '♧' ]
const result =
ranks.flatMap(r =>
suits.flatMap(s =>
[[r, s]]
)
)
console.log(JSON.stringify(result))
// [ ['J','♡'], ['J','♢'], ['J','♤'], ['J','♧']
// , ['Q','♡'], ['Q','♢'], ['Q','♤'], ['Q','♧']
// , ['K','♡'], ['K','♢'], ['K','♤'], ['K','♧']
// , ['A','♡'], ['A','♢'], ['A','♤'], ['A','♧']
// ]
Array.prototype._mylib_flatMap
単にを定義するのではなく、プロトタイプへの追加を名前空間化する(たとえば)か、ES6シンボルを使用する方がよいと考えられますArray.prototype.flatMap
。
map
グローバル関数として定義された関数型コードを想像してください!2番目は悪い習慣です
append
、map
、filter
、foldl
、foldr
デフォルトの名前空間の無数の他の中。誰かが「グローバルは悪い」または「ネイティブの拡張は悪い」と言うのを聞いたので、それは悪い習慣にはなりません-ラケットは最高に設計された言語の1つです。あなたはそれを適切に行う方法/時期がわからないだけです。
flatMap
ES2019(ES10)の一部としてTC39によって承認されています。次のように使用できます。
[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
これが私自身のメソッドの実装です:
const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])
flapMap
ですか?マップをフラップするのではなく、フラットにしたいのです。
const flatMap = (arr, ...args) => [].concat(...arr.map(...args));
を使用apply
することです(またはspread演算子を使用できない場合は使用します)-このconcatバージョンには、以下のソリューションで説明されているように、巨大な配列の呼び出しスタックサイズの問題があります
自分で定義したくないとおっしゃっていたのは知っていますが、この実装は非常に簡単な定義です。
同じgithubページからもこれがあります:
これは、es6 Spreadを使用する少し短い方法で、renaudtertraisと同様ですが、es6を使用し、プロトタイプに追加しません。
var flatMap = (a, cb) => [].concat(...a.map(cb))
const s = (v) => v.split(',')
const arr = ['cat,dog', 'fish,bird']
flatMap(arr, s)
これらのどちらかが役に立ちますか?
この後者の「ソリューション」は、非常に大きな(たとえば、300k要素)配列で呼び出された場合、「最大呼び出しスタックサイズを超えた」という問題が発生することに注意してください(@ftorのおかげです)a
。
[].concat(...(new Array(300000).fill("foo").map(x => x.toUpperCase())))
。確かに、それはコーナーケースです。しかし、少なくともそれについて言及する必要があります。
Lodashはフラットマップ関数を提供します。これは私にとってはJavascriptがネイティブに提供するのと実質的に同等です。Lodashユーザーでない場合は、ES6のArray.reduce()
方法で同じ結果が得られますが、マップしてから個別のステップでフラット化する必要があります。
以下は、各メソッドの例であり、整数のリストをマッピングし、オッズのみを返します。
Lodash:
_.flatMap([1,2,3,4,5], i => i%2 !== 0 ? [i] : [])
ES6リデュース:
[1,2,3,4,5].map(i => i%2 !== 0 ? [i] : []).reduce( (a,b) => a.concat(b), [] )
私はこのようなことをしました:
Array.prototype.flatMap = function(selector){
return this.reduce((prev, next) =>
(/*first*/ selector(prev) || /*all after first*/ prev).concat(selector(next)))
}
[[1,2,3],[4,5,6],[7,8,9]].flatMap(i => i); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
[{subarr:[1,2,3]},{subarr:[4,5,6]},{subarr:[7,8,9]}].flatMap(i => i.subarr); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
{ "message": "Uncaught TypeError: [1,2,3].flatMap is not a function", "filename": "https://stacksnippets.net/js", "lineno": 15, "colno": 23 }
Array.prototype.flatMap()
JSに到着しました。ただし、すべてのブラウザがそれらをサポートしているわけではなく、MozillaWebドキュメントで現在のブラウザの互換性を確認してください。
何 flatMap()
メソッドは、最初にコールバック関数を引数として使用して各要素をマップし、次に結果を新しい配列にフラット化します(要素がフラット化されるため、2d配列は1dになります)。
関数の使用方法の例もあります。
let arr = [[2], [4], [6], [8]]
let newArr = arr.flatMap(x => [x * 2]);
console.log(newArr);
arr.reduce((arr, v) => (arr.push(...v), arr), [])
ですか?