JavaScript / jQueryの配列から複数の要素を削除する


117

2つのアレイがあります。最初の配列にはいくつかの値が含まれ、2番目の配列には最初の配列から削除する必要がある値のインデックスが含まれています。例えば:

var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);

私はインデックスに値の存在を削除したい0,2,4からvaluesArr。私はネイティブのsplice方法が役立つかもしれないと思ったので、私は思いつきました:

$.each(removeValFromIndex,function(index,value){
    valuesArr.splice(value,1);
});

しかし、それぞれの後spliceに、の値のインデックスvaluesArrが異なるため、機能しませんでした。一時的な配列を使用してすべての値を2番目の配列にコピーすることでこの問題を解決できましたが、配列から値を削除するために複数のインデックスを渡すことができるネイティブメソッドがあるかどうか疑問に思っていました。

私はjQueryソリューションを好みます。(grepここで使用できるかどうかはわかりません)

回答:


255

いつも昔ながらのforループがあります:

var valuesArr = ["v1","v2","v3","v4","v5"],
    removeValFromIndex = [0,2,4];    

for (var i = removeValFromIndex.length -1; i >= 0; i--)
   valuesArr.splice(removeValFromIndex[i],1);

経るremoveValFromIndex逆の順序でとすることができます.splice()まだツー・削除されるアイテムのインデックスをめちゃくちゃにせずに。

上記では、2つの配列を宣言するために角かっこ付きの配列リテラル構文を使用していることに注意してください。new Array()渡されるパラメーターの数に応じて応答が異なるため、混乱を招く可能性があるため、これは推奨される構文です。

編集:必ずしも特定の順序になっているとは限らないインデックスの配列に関する別の答えについてのコメントを見ただけです。その場合は、開始する前に降順で並べ替えてください。

removeValFromIndex.sort(function(a,b){ return b - a; });

そして、$.each()あなたが好きなループ/ /などの方法でそれに従ってください。


1
インデックスをめちゃくちゃにしないでください
Muhammad Umer 2013

5
@MuhammadUmer-いいえ、あなたが正しくそれをしなければ、それは私の答えが説明するものです。
nnnnnn

5
逆順認識に感謝します。
Daniel Nalbach、2015

2
+1、スプライスを逆の順序で行う必要があることに気付きませんでしたが、forEachを使用する代わりに、私のアプローチは使用しています$.each(rvm.reverse(), function(e, i ) {})
Luis Stanley Jovel

1
これremoveValFromIndex は、が昇順で並べ替えられている場合にのみ機能します
Kunal Burangi '21

24

これは、lodash / underscoreを使用しない場合に使用するものです。

while(IndexesToBeRemoved.length) {
    elements.splice(IndexesToBeRemoved.pop(), 1);
}

エレガントなソリューション!最初はこれは機能しないだろうと思ったのは、呼び出すたびsliceに削除するインデックスを再計算する必要があると思ったからです(-1 on IndexestoBeRemoved)が、実際には機能します。
Renato Gama

2
あまりにも賢い
Farzad YZ

11
このソリューションは、IndexesToBeRemoved配列のみが昇順でソートされている場合に機能します。
xfg 2017年

これらのインデックスは、最初のスプライス後に無効になります。
しんぞう2018年

@shinzou- IndexesToBeRemovedソートされていない場合(昇順)。
nnnnnn

18

in-placeできませんがgrep、のinArray機能を使用して実行できますjQuery

var arr = $.grep(valuesArr, function(n, i) {
    return $.inArray(i, removeValFromIndex) ==-1;
});

alert(arr);//arr contains V2, V4

このフィドルを確認してください。


あなたが言ったならそれは(十分に近い)インプレースになるでしょうvaluesArr = $.grep(...);
nnnnnn

1
@nnnnnnはははははははははははははははははははははははははははははははばい(とても生産的なのでご存知でしょう)ので、あまり実験しませんでした。
TheVillageIdiot

1
@ cept0なぜ反対票か OPはjQueryソリューションを求めました。
Ste77、2014年

どうもありがとうございます!@TheVillageIdiot
ecorvo

jsfiddler-エラー404。本当に申し訳ありませんが、そのようなページはありません。
Ash


7
function filtermethod(element, index, array) {  
    return removeValFromIndex.find(index)
}  
var result = valuesArr.filter(filtermethod);

MDNリファレンスはこちら


@ riship89フィドルがダウンしている
mate64 2014年

@カルナ:フィドルがダウンしている
riship89

1
執筆時点(2014年6月)では、Array.prototype.findは現在のES6ドラフトの一部であり、現在のfirefoxで
Olli K

6

純粋なJSでは、配列を逆方向にループできるためsplice()、ループの次の要素のインデックスを台無しにすることはありません。

for (var i = arr.length - 1; i >= 0; i--) {
    if ( yuck(arr[i]) ) {
        arr.splice(i, 1);
    }
}

yuckは機能しないため、機能しないため、不要な要素のインデックスのインデックスであると想定し、yuck [arr [i]]を使用
DavChana

5

O(n)時間とともに回答を投稿する必要があります:) スプライスソリューションの問題は、基になるarrayの実装が文字通りarrayであるため、各splice呼び出しにO(n)時間がかかることです。これは、この動作を利用する例を設定するときに最も顕著です。

var n = 100
var xs = []
for(var i=0; i<n;i++)
  xs.push(i)
var is = []
for(var i=n/2-1; i>=0;i--)
  is.push(i)

これにより、中間から開始までの要素が削除されます。したがって、削除するたびにjsエンジンがn/2要素をコピーするように強制されます(n/2)^2。合計で2次のコピー操作があります。

スプライスソリューション(isオーバーヘッドを取り除くために、既に降順で並べ替えられていると想定)は次のようになります。

for(var i=0; i<is.length; i++)
  xs.splice(is[i], 1)

ただし、配列を最初から再構成し、マスクを使用して要素をコピーするかどうかを確認することにより、線形時間ソリューションを実装することは難しくありません(ソートによってこれがにプッシュされますO(n)log(n))。以下はそのような実装です(mask速度のためにブール値を反転したものではありません)。

var mask = new Array(xs.length)
for(var i=is.length - 1; i>=0; i--)
  mask[is[i]] = true
var offset = 0
for(var i=0; i<xs.length; i++){
  if(mask[i] === undefined){
    xs[offset] = xs[i]
    offset++
  }
}
xs.length = offset

私はこれをjsperf.comで実行しましたがn=100、スプライス方法でも完全に90%遅くなります。nこの差が大きくなると、はるかに大きくなります。


5

クイックES6ワンライナー:

const valuesArr = new Array("v1","v2","v3","v4","v5");   
const removeValFromIndex = new Array(0,2,4);

const arrayWithValuesRemoved = valuesArr.filter((value, i) => removeValFromIndex.includes(i))

の代わりにを使用して使用するとremoveValFromIndex、コードの実行が速くなるはずです。Set()removeValFromIndex.hasincludes
ボリス

5

filterSetを使用したシンプルで効率的な(線形複雑度)ソリューション:

const valuesArr = ['v1', 'v2', 'v3', 'v4', 'v5'];   
const removeValFromIndex = [0, 2, 4];

const indexSet = new Set(removeValFromIndex);

const arrayWithValuesRemoved = valuesArr.filter((value, i) => !indexSet.has(i));

console.log(arrayWithValuesRemoved);

その実装の大きな利点は、Set lookup操作(has関数)が一定の時間を要することです。たとえば、nevaceの回答よりも高速です。


@MichaelPaccione喜んでお手伝いします:)
Alberto Trindade Tavares

3

これは私にとってはうまく機能し、オブジェクトの配列から削除するときにも機能します。

var array = [ 
    { id: 1, name: 'bob', faveColor: 'blue' }, 
    { id: 2, name: 'jane', faveColor: 'red' }, 
    { id: 3, name: 'sam', faveColor: 'blue' }
];

// remove people that like blue

array.filter(x => x.faveColor === 'blue').forEach(x => array.splice(array.indexOf(x), 1));

これを書くためのより短い効率的な方法があるかもしれませんが、これはうまくいきます。


2

ES5を使用したシンプルなソリューション。多くの人がjQueryなどに依存することを望まなくなったため、これは現在のほとんどのアプリケーションに適しているようです。

削除するインデックスが昇順でソートされている場合:

var valuesArr = ["v1", "v2", "v3", "v4", "v5"];   
var removeValFromIndex = [0, 2, 4]; // ascending

removeValFromIndex.reverse().forEach(function(index) {
  valuesArr.splice(index, 1);
});

削除するインデックスがソートされていない場合:

var valuesArr = ["v1", "v2", "v3", "v4", "v5"];   
var removeValFromIndex = [2, 4, 0];  // unsorted

removeValFromIndex.sort(function(a, b) { return b - a; }).forEach(function(index) {
  valuesArr.splice(index, 1);
});

1

あなたは置き換えることによって、あなたのコードを修正することができremoveValFromIndexremoveValFromIndex.reverse()。その配列で昇順の使用が保証されていない場合は、代わりにを使用できますremoveValFromIndex.sort(function(a, b) { return b - a })


私にはよく見えます-jsfiddle.net/mrtsherman/gDcFu/2。ただし、これは削除リストが正しいことを前提としています。
mrtsherman

@minopret:ありがとうございます。ただし、インデックスremoveValFromIndexが昇順の場合にのみ機能します。
xyz


1

underscore.jsを使用している場合、を使用_.filter()して問題を解決できます。

var valuesArr = new Array("v1","v2","v3","v4","v5");
var removeValFromIndex = new Array(0,2,4);
var filteredArr = _.filter(valuesArr, function(item, index){
                  return !_.contains(removeValFromIndex, index);
                });

さらに、インデックスの代わりにアイテムのリストを使用してアイテムを削除しようとしている場合は_.without()、次のように単純にを使用できます。

var valuesArr = new Array("v1","v2","v3","v4","v5");
var filteredArr = _.without(valuesArr, "V1", "V3");

filteredArr["V2", "V4", "V5"]


どのように包含がアンダースコアに実装されているか...フィルター内のindexOfと同等である場合は注意してください...まったく最適ではありません...
Alvaro Joao


1

こちらがクイックです。

function removeFromArray(arr, toRemove){
    return arr.filter(item => toRemove.indexOf(item) === -1)
}

const arr1 = [1, 2, 3, 4, 5, 6, 7]
const arr2 = removeFromArray(arr1, [2, 4, 6]) // [1,3,5,7]

フィルター内部のindexOf ...最適ではない
Alvaro Joao

0

Applyのような音があなたが探しているものかもしれません。
多分このような何かがうまくいくでしょうか?

Array.prototype.splice.apply(valuesArray, removeValFromIndexes );

ただし、この.splice()メソッドは、要素のリストが削除されることを期待していません。削除を開始する要素の単一のインデックスの後に、削除する要素の数が続くことを期待しています...
nnnnnn

0

複数のアイテムまたは一意のアイテムの場合:

Array.prototype.filterを使用することをお勧めします

すでにインデックスがわかっている場合は、indexOfを使用しないでください!:

var valuesArr = ["v1","v2","v3","v4","v5"];
var removeValFrom = [0, 2, 4];

valuesArr = valuesArr.filter(function(value, index) {
     return removeValFrom.indexOf(index) == -1;
}); // BIG O(N*m) where N is length of valuesArr and m is length removeValFrom

行う:

ハッシュで... Array.prototype.mapを使用

  var valuesArr = ["v1","v2","v3","v4","v5"];
  var removeValFrom = {};
  ([0, 2, 4]).map(x=>removeValFrom[x]=1); //bild the hash.
  valuesArr = valuesArr.filter(function(value, index) {
      return removeValFrom[index] == 1;
  }); // BIG O(N) where N is valuesArr;

0
var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);

console.log(valuesArr)
let arr2 = [];

for (let i = 0; i < valuesArr.length; i++){
  if (    //could also just imput this below instead of index value
    valuesArr[i] !== valuesArr[0] && // "v1" <--
    valuesArr[i] !== valuesArr[2] && // "v3" <--
    valuesArr[i] !== valuesArr[4]    // "v5" <--
  ){
    arr2.push(valuesArr[i]);
  }
}

console.log(arr2);

これは機能します。ただし、その過程で新しい配列を作成します。それが必要かどうかはわかりませんが、技術的には必要な値のみを含む配列になります。


-1

delete array[index]これを試して使用することもできます。これは要素を完全に削除するのではなく、値をに設定しますundefined


おかげで、要素を削除したいと思います。
xyz

-1

あなたは構築できSet、アレイから、その後のセットから配列を作成します。

const array = [1, 1, 2, 3, 5, 5, 1];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // Result: [1, 2, 3, 5]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.