JavaScript で Array.map を使用して要素を削除する
質問
を使用して項目の配列をフィルタリングしたいと考えています。 map()
関数。コードスニペットは次のとおりです。
var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
});
問題は、フィルターで除外された項目がまだ配列内のスペースを使用しているため、それらを完全に消去したいことです。
何か案が?
編集:ありがとう、忘れてた filter()
, 、私が望んでいたのは実際には filter()
それから map()
.
編集2:指摘してくれてありがとう map()
そして filter()
私の特定のコードはブラウザーで実行することを意図したものではありませんが、すべてのブラウザーに実装されているわけではありません。
解決
を使用する必要があります。 filter
フィルタリングに加えて配列内の項目を変更する場合を除き、マップではなくメソッドを使用します。
例えば。
var filteredItems = items.filter(function(item)
{
return ...some condition...;
});
[編集:もちろん、いつでも行うことができます sourceArray.filter(...).map(...)
フィルターと変更の両方を行う]
他のヒント
少し前に回答を書きましたが、意見が変わりました。私のものをチェックすることをお勧めします ブログ投稿 これにより、このトピックが拡張され、よりわかりやすく説明されます。また、代替案の最後に JSperf の比較も示します。
内容は次のとおりです。求めていること (1 つの関数呼び出し内でのフィルタリングとマッピング) を達成するには、次を使用する必要があります。 Array.reduce()
. 。しかし より読みやすい そして 通常は速い2 アプローチは、フィルターとマップを連鎖的に使用することです。
[1,2,3].filter(num => num > 2).map(num => num * 2)
以下はその方法の説明です Array.reduce()
の動作と、それを使用して 1 回の反復でフィルターとマップを実行する方法を説明します。これがあまりに凝縮されている場合は、上にリンクされているブログ投稿を参照することを強くお勧めします。これは、明確な例と進行状況を含む、より親しみやすい紹介文です。
Reduce に (通常は匿名の) 関数である引数を与えます。
その無名関数 2 つのパラメータを取ります。1 つは (map/filter/forEach に渡される匿名関数と同様) 操作対象の反復対象です。reduce に渡される匿名関数には別の引数がありますが、これらの関数は受け入れません。 関数呼び出し間で渡される値。多くの場合、 メモ.
Array.filter() は引数 (関数) を 1 つだけ取りますが、Array.reduce() は重要な (ただしオプションの) 2 番目の引数も取ることに注意してください。「memo」の初期値。最初の引数として匿名関数に渡され、その後、関数呼び出し間で変更して渡すことができます。(これが指定されていない場合、最初の匿名関数呼び出しの 'memo' がデフォルトで最初の iteratee になり、'iteratee' 引数は実際には配列の 2 番目の値になります)
私たちの場合、空の配列を渡して開始し、関数に基づいて配列に iteratee を注入するかどうかを選択します。これがフィルタリング プロセスです。
最後に、各匿名関数呼び出しで「進行中の配列」を返し、reduce はその戻り値を受け取り、それを引数 (メモと呼ばれる) として次の関数呼び出しに渡します。
これにより、フィルターとマップを 1 回の反復で実行できるようになり、必要な反復回数が半分に減ります。:)
より完全な説明については、を参照してください。 MDN または上記のリンクから。:)
Reduce 呼び出しの基本的な例:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
// if condition is our filter
if (iteratee > 1) {
// what happens inside the filter is the map
memo.push(iteratee * 2);
}
// this return value will be passed in as the 'memo' argument
// to the next call of this function, and this function will have
// every element passed into it at some point.
return memo;
}, initialMemo)
console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
より簡潔なバージョン:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
最初の反復対象が 1 より大きくなかったため、フィルターされたことに注意してください。また、initialMemo にも注目してください。これは、その存在を明確にして注意を引くためだけに名前が付けられています。もう一度、最初の匿名関数呼び出しに「memo」として渡され、次に匿名関数の戻り値が「memo」引数として次の関数に渡されます。
メモの古典的な使用例のもう 1 つは、配列内の最小値または最大値を返すことです。例:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
// ^this would return the largest number in the list.
独自のreduce関数を記述する方法の例(これは、このような関数を理解するのに役立つことが多いと思います):
test_arr = [];
// we accept an anonymous function, and an optional 'initial memo' value.
test_arr.my_reducer = function(reduceFunc, initialMemo) {
// if we did not pass in a second argument, then our first memo value
// will be whatever is in index zero. (Otherwise, it will
// be that second argument.)
const initialMemoIsIndexZero = arguments.length < 2;
// here we use that logic to set the memo value accordingly.
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
// here we use that same boolean to decide whether the first
// value we pass in as iteratee is either the first or second
// element
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
// memo is either the argument passed in above, or the
// first item in the list. initialIteratee is either the
// first item in the list, or the second item in the list.
memo = reduceFunc(memo, this[i]);
}
// after we've compressed the array into a single value,
// we return it.
return memo;
}
実際の実装では、たとえばインデックスなどにアクセスできますが、これがその要点を簡単に理解するのに役立つことを願っています。
それはマップが行うことではありません。本当に欲しいのは 配列フィルター. 。または、本当に元のリストから要素を削除したい場合は、for ループを使用して命令的に削除する必要があります。
ただし、次のことに注意する必要があります。 Array.filter
すべてのブラウザでサポートされているわけではないため、プロトタイプを作成する必要があります。
//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
{
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}
そうすることで、必要なメソッドのプロトタイプを作成できます。
このページで共有されているポリフィルがひどいため、この回答をここに配置しています
function reduce(f, y, xs, context) {
var acc = y;
for (var i = 0, len = xs.length; i < len; i++)
acc = f.call(context, acc, xs[i], i, xs);
return acc;
}
function reduce1(f, xs, context) {
if (xs.length === 0)
throw Error('cannot reduce empty array without initial value');
else
return reduce(f, xs[0], xs.slice(1), context);
}
function map(f, xs, context) {
return reduce(function(acc, x, i) {
return acc.concat([
f.call(context, x, i, xs)
]);
}, [], xs);
}
function filter(f, xs, context) {
return reduce(function(acc, x, i) {
if (f.call(context, x, i, xs))
return acc.concat([x]);
else
return acc;
}, [], xs);
}
プロトタイプを拡張する
if (Array.prototype.reduce === undefined) {
Array.prototype.reduce = function(f, initialValue, context) {
if (initialValue === undefined)
return reduce1(f, this, context);
else
return reduce(f, initialValue, this, context);
};
}
if (Array.prototype.map === undefined) {
Array.prototype.map = function(f, context) {
return map(f, this, context);
};
}
if (Array.prototype.filter === undefined) {
Array.prototype.filter = function(f, context) {
return filter(f, this, context);
};
}
var arr = [1,2,'xxx','yyy']
arr = arr.filter(function(e){ return e != 'xxx' });
arr // [1, 2, "yyy"]