49

map()関数を使用して項目の配列をフィルタリングしたいとします。JavaScriptでArray.mapを使用して要素を削除する

var filteredItems = items.map(function(item) 
{ 
    if(...some condition...) 
    { 
     return item; 
    } 
}); 

問題は、フィルタされたアイテムがまだ配列内のスペースを使用しているため、それらを完全に消去したいということです。

編集:ありがとう、私は約filter()を忘れていましたが、実際にはfilter()、次にmap()です。

EDIT2:map()filter()はすべてのブラウザで実装されていませんが、私の特定のコードはブラウザでは実行できませんでした。

+0

マップ 'と反復を倍増するのではなく、' reduce'を使用することを検討してください - >フィルタ '。私は、この質問に来る人々が答えを見ずに間違ってこれを読んで、最終的にはより良い方法があることを学ぶことを心配しています。 –

+0

なぜ2回の反復が1回最悪であるのかを詳しく説明できますか?つまり、2 * O(n)は私にはO(2 * n)に相当します... –

+0

はい、20 * 2と10 * 4は同じです...しかし、同じ数の操作フィルタ/マップ関数内で実行される場合、関数呼び出しの数を倍にしてそのようにすることができます。フィルタ(f) - >マップ(g)対縮小(h)。すべての関数呼び出しにはコストがかかります。 (はい、一般的に無視しても構いませんが、map/filter/reduceは非常に大きなリストで使用される関数の型です。 私はあとでいくつかのjsperfテストを実行して、その時点で私の答えとこのコメントを説明(検証)して更新しようとします。 (それ以外は、これを減らすための理想的なユースケースです) –

答えて

64

フィルタに加えて、アレイ内の項目を変更しない限り、マップではなくfilterメソッドを使用する必要があります。

例えば、

var filteredItems = items.filter(function(item) 
{ 
    return ...some condition...; 
}); 

[編集:もちろん、あなたは常に両方のフィルタにsourceArray.filter(...).map(...)を行うと、変異させることができ]

+1

'map'は変更されません – naomik

+6

しかし' map'で突然変異を起こすことができます。 –

11

地図とは異なります。あなたは本当にArray.filterがほしいと思う。または、元のリストから要素を削除したい場合は、forループを使用して必須にする必要があります。

4

あなたは、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; 
    }; 
} 

これを行うと、必要な方法をプロトタイプできます。

1
var arr = [1,2,'xxx','yyy'] 

arr = arr.filter(function(e){ return e != 'xxx' }); 

arr // [1, 2, "yyy"] 
+1

'var arr = [1,2、" xxx "、" yyy "]; \t \t \t ARR = arr.filter(関数(E){ \t \t \t \tリターンE!= "XXX" \t \t \t}) \t \t \tにconsole.log(ARR)ブリリアント ' –

22

実際には、受け入れられた回答はあなたを変えています。

http://elijahmanor.com/reducing-filter-and-map-down-to-reduce/

しかし、私はちょうどリンクを入れないで、ここでのショートバージョンがあります:あなたは本当に、ラを減らす使用することにしたいです。

あなたはreduce引数に(通​​常は匿名の)関数を指定します。

匿名関数は、2つのパラメータ(map/filter/forEachに渡される匿名関数のような)をとるもので、操作対象のiterateeです。しかし、関数呼び出しの間に渡される値はであり、しばしばメモと呼ばれる値であることを意味しています。

Array.filter()は1つの引数(関数)しか取るわけではありませんが、Array.reduce()は重要な(ただしオプションですが)第2引数をとります: 'memo'の初期値匿名関数を最初の引数として使用し、その後、関数呼び出しの間で変更して渡すことができます。(提供されていなければ、最初の匿名関数呼び出しの 'memo'は最初のiterateeになり、 'iteratee'引数は実際に配列の2番目の値になります)

私たちの場合、空の配列を渡して開始し、次にiterateeを配列に挿入するかどうかを関数に基づいて行うかどうかを選択します。これがフィルタリングプロセスです。

最後に、各無名関数呼び出しで 'array in progress'を返し、reduceはその戻り値をとり、引数(memo)として次の関数呼び出しに渡します。

これにより、フィルタとマップを1回の反復で実行できるため、必要な反復回数を半減できます。 :)

詳細については、MDNまたは上記のリンクを参照してください。 :)削減コールの

Basicの例:

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)] 

より簡潔版:最初iterateeが1より大きいなかったし、そうで濾過したことを

[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, []) 

は注意してください。また、その存在を明確にして注意を引くためにちょうど命名されたinitialMemoに注意してください。再び、それは最初の無名関数呼び出しに「メモ」として渡され、無名関数の戻り値は「メモ」引数として次の関数に渡されます。

メモの古典的な使用例のもう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. 

独自のものを作成する方法の例は、機能を減らす(これは多くの場合、私は見つけるこのような理解の機能を助けます):私は徹底的にその実装をテストしていない

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; 
} 

、とだけ私の頭の上からそれを書きましたが、私の2つの基本的なテストケースではうまくいくようでした。実際の実装では、例えば索引のようなものにアクセスすることができますが、これがその要点を複雑ではないと感じるのを助けてくれることを願っています。

+1

!私は何年もこのようなことをしたいと思っていました。素敵なやり方やうわー、自然なjavascriptを試してみることにしました! – jemiloii

3

私は、このページ上で共有polyfillsはひどいですので、ここでは、この答えを配置することだ

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); 
    }; 
} 
関連する問題