Hapus beberapa elemen dari array di Javascript / jQuery

117

Saya memiliki dua array. Larik pertama berisi beberapa nilai sedangkan larik kedua berisi indeks nilai yang harus dihapus dari larik pertama. Sebagai contoh:

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

Saya ingin menghapus nilai yang ada di indeks 0,2,4dari valuesArr. Saya pikir splicemetode asli mungkin membantu jadi saya datang dengan:

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

Tetapi itu tidak berhasil karena setelah masing-masing splice, indeks nilai di dalamnya valuesArrberbeda. Saya bisa menyelesaikan masalah ini dengan menggunakan array sementara dan menyalin semua nilai ke array kedua, tetapi saya bertanya-tanya apakah ada metode asli yang dapat kami lewati beberapa indeks untuk menghapus nilai dari array.

Saya lebih suka solusi jQuery. (Tidak yakin apakah saya bisa menggunakan di grepsini)

xyz
sumber

Jawaban:

256

Selalu ada forlingkaran lama yang polos :

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

Pergi melalui removeValFromIndexdalam urutan terbalik dan Anda bisa .splice()tanpa mengacaukan indeks item yang belum dihapus.

Catatan di atas saya telah menggunakan sintaks array-literal dengan tanda kurung siku untuk menyatakan dua array. Ini adalah sintaks yang disarankan karena new Array()penggunaan berpotensi membingungkan mengingat responsnya berbeda tergantung pada berapa banyak parameter yang Anda berikan.

EDIT : Baru saja melihat komentar Anda di jawaban lain tentang array indeks tidak harus dalam urutan tertentu. Jika demikian, urutkan saja ke dalam urutan menurun sebelum Anda mulai:

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

Dan ikuti itu dengan $.each()metode perulangan / / dll yang Anda suka.

nnnnnn
sumber
1
tidak akan mengacaukan mengacaukan indeks
Muhammad Umer
5
@MuhammadUmer - Tidak, tidak jika Anda melakukannya dengan benar, itulah jawaban saya.
nnnnnn
5
Terima kasih atas kesadaran pesanan terbalik.
Daniel Nalbach
2
+1, saya tidak menyadari bahwa saya harus melakukan sambungan dalam urutan terbalik, meskipun alih-alih menggunakan forEach, pendekatan saya menggunakan$.each(rvm.reverse(), function(e, i ) {})
Luis Stanley Jovel
1
ini hanya akan berfungsi jika removeValFromIndex diurutkan dalam urutan menaik
Kunal Burangi
24

Ini salah satu yang saya gunakan saat tidak menggunakan lodash / garis bawah:

while(IndexesToBeRemoved.length) {
    elements.splice(IndexesToBeRemoved.pop(), 1);
}
Dan Ochiana
sumber
Solusi yang elegan! Awalnya saya pikir ini tidak akan berhasil karena saya pikir setiap kali Anda menelepon sliceAnda harus menghitung ulang indeks yang akan dihapus (-1 on IndexestoBeRemoved), tetapi itu benar-benar berfungsi!
Renato Gama
2
Terlalu pintar
Farzad YZ
11
Solusi ini bekerja jika hanya IndexesToBeRemovedarray yang diurutkan secara ascending.
xfg
Indeks tersebut akan dibatalkan setelah sambungan pertama.
shinzou
@shinzou - Tidak jika IndexesToBeRemoveddiurutkan (naik).
nnnnnn
18

Tidak in-placetetapi dapat dilakukan dengan menggunakan grepdan inArrayfungsi jQuery.

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

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

periksa biola ini .

TheVillageIdiot
sumber
Ini akan (cukup dekat) di tempat jika Anda baru saja mengatakanvaluesArr = $.grep(...);
nnnnnn
1
@nnnnnn ha ha ha Saya pergi untuk rapat (Anda tahu mereka membuat Anda sangat produktif) jadi tidak banyak bereksperimen.
TheVillageIdiot
1
@ cept0 Mengapa downvote? OP meminta solusi jQuery.
Ste77
Terima kasih banyak! @TheVillageIdiot
ecorvo
jsfiddler - Kesalahan 404. Kami benar-benar minta maaf, tetapi tidak ada halaman seperti itu.
Ash
17

Saya sarankan Anda menggunakan Array.prototype.filter

var valuesArr = ["v1","v2","v3","v4","v5"];
var removeValFrom = [0, 2, 4];
valuesArr = valuesArr.filter(function(value, index) {
     return removeValFrom.indexOf(index) == -1;
})
Саша Давиденко
sumber
indexOf di dalam filter ... tidak optimal
Alvaro Joao
1
suara positif. lebih cepat daripada metode sambungan menurut jsperf.com/remove-multiple/1
lionbigcat
Bagus! Sekarang saya bisa tidur :)
Firmansyah
7
function filtermethod(element, index, array) {  
    return removeValFromIndex.find(index)
}  
var result = valuesArr.filter(filtermethod);

Referensi MDN ada di sini

riship89.dll
sumber
@ riship89 Biola sedang turun
mate64
@Karna: biola turun
riship89
1
Harap perhatikan bahwa pada saat penulisan (Juni 2014), Array.prototype.find adalah bagian dari draf ES6 saat ini dan hanya diterapkan di firefox
Olli K
6

Dalam JS murni Anda dapat melakukan perulangan melalui array ke belakang, jadi splice()tidak akan mengacaukan indeks elemen berikutnya dalam perulangan:

for (var i = arr.length - 1; i >= 0; i--) {
    if ( yuck(arr[i]) ) {
        arr.splice(i, 1);
    }
}
Watchduck
sumber
Tidak bekerja yuck bukan fungsi, jadi diasumsikan itu adalah indeks indeks elemen yang tidak diinginkan, & digunakan yuck [arr [i]]
DavChana
5

Rasanya perlu mengirim jawaban dengan O(n)waktu :). Masalah dengan solusi sambatan adalah karena implementasi yang mendasari array secara harfiah adalah array , setiap splicepanggilan akan memakan O(n)waktu. Ini paling jelas saat kami menyiapkan contoh untuk mengeksploitasi perilaku ini:

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)

Ini menghapus elemen mulai dari tengah ke awal, oleh karena itu setiap menghapus memaksa mesin js untuk menyalin n/2elemen, kami memiliki (n/2)^2operasi penyalinan total yang kuadrat.

Solusi sambungan (dengan asumsi issudah diurutkan dalam urutan menurun untuk menghilangkan overhead) berjalan seperti ini:

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

Namun, tidak sulit untuk mengimplementasikan solusi waktu linier, dengan membangun kembali array dari awal, menggunakan mask untuk melihat apakah kita menyalin elemen atau tidak (sort akan mendorong ini ke O(n)log(n)). Berikut ini adalah implementasi seperti itu (bukan maskboolean terbalik untuk kecepatan):

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

Saya menjalankan ini di jsperf.com dan bahkan n=100metode sambungannya 90% lebih lambat. Untuk lebih besar nperbedaan ini akan jauh lebih besar.

simonzack
sumber
5

ES6 cepat satu liner:

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))
nevace
sumber
Kode Anda harus berjalan lebih cepat jika Anda membuat removeValFromIndexsebuah Set()dan menggunakan removeValFromIndex.hasbukan includes.
Boris
5

Solusi sederhana dan efisien (kompleksitas linier) menggunakan filter dan Set :

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

Keuntungan besar dari implementasi itu adalah bahwa operasi Set lookup ( hasfungsi) membutuhkan waktu yang konstan, menjadi lebih cepat daripada jawaban nevace, misalnya.

Alberto Trindade Tavares
sumber
@MichaelPaccione Senang membantu :)
Alberto Trindade Tavares
3

Ini berfungsi dengan baik untuk saya dan berfungsi saat menghapus dari larik objek juga:

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

Mungkin ada cara yang lebih singkat dan lebih efisien untuk menulis ini, tetapi ini berhasil.

StuartMc
sumber
2

Solusi sederhana menggunakan ES5. Ini tampaknya lebih sesuai untuk sebagian besar aplikasi saat ini, karena banyak yang tidak lagi ingin bergantung pada jQuery dll.

Saat indeks yang akan dihapus diurutkan dalam urutan menaik:

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

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

Ketika indeks yang akan dihapus tidak diurutkan:

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);
});
Kaspar Fenner
sumber
1

Anda dapat memperbaiki kode Anda dengan mengganti removeValFromIndexdengan removeValFromIndex.reverse(). Jika larik tersebut tidak dijamin untuk menggunakan urutan naik, Anda dapat menggunakan removeValFromIndex.sort(function(a, b) { return b - a }).

minopret
sumber
Kelihatannya bagus untuk saya - jsfiddle.net/mrtsherman/gDcFu/2 . Meskipun ini membuat anggapan bahwa daftar penghapusan sesuai.
mrtsherman
@minopret: Terima kasih, tetapi ini hanya akan berfungsi jika indeks dalam removeValFromIndexurutan menaik.
xyz
1

Jika Anda menggunakan underscore.js , Anda dapat menggunakannya _.filter()untuk memecahkan masalah Anda.

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

Selain itu, jika Anda mencoba menghapus item menggunakan daftar item, bukan indeks, Anda dapat menggunakan _.without(), seperti:

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

Sekarang filteredArrharus["V2", "V4", "V5"]

Johnny Zhao
sumber
Bagaimana isi diterapkan di garis bawah ... hati-hati jika itu setara dengan indexOf di dalam filter ... tidak optimal sama sekali ...
Alvaro Joao
1

filter + indexOf (IE9 +):

function removeMany(array, indexes) {
  return array.filter(function(_, idx) {
    return indexes.indexOf(idx) === -1;
  });
}); 

Atau dengan filter ES6 + temukan (Edge +):

function removeMany(array, indexes = []) {
  return array.filter((_, idx) => indexes.indexOf(idx) === -1)
}
daviestar
sumber
indexOf di dalam filter ... tidak optimal
Alvaro Joao
1

Ini quickie.

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]
Merrick Kavolsky
sumber
indexOf di dalam filter ... tidak optimal
Alvaro Joao
0

Kedengarannya Apply bisa jadi apa yang Anda cari.
mungkin sesuatu seperti ini akan berhasil?

Array.prototype.splice.apply(valuesArray, removeValFromIndexes );
rampok
sumber
Tetapi .splice()metode ini tidak mengharapkan daftar elemen yang akan dihapus, metode ini mengharapkan indeks tunggal elemen yang akan mulai dihapus diikuti dengan jumlah elemen yang akan dihapus ...
nnnnnn
0

Untuk Beberapa item atau item unik:

Saya sarankan Anda menggunakan Array.prototype.filter

Jangan pernah menggunakan indexOf jika Anda sudah mengetahui indeksnya !:

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

Melakukan:

dengan Hash ... menggunakan 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;
Alvaro Joao
sumber
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);

Ini bekerja. Namun, Anda akan membuat array baru dalam prosesnya. Tidak yakin apakah itu yang Anda inginkan atau tidak, tetapi secara teknis itu akan menjadi array yang hanya berisi nilai yang Anda inginkan.


sumber
-1

Anda dapat mencoba dan menggunakan delete array[index]Ini tidak akan sepenuhnya menghapus elemen melainkan menetapkan nilainya ke undefined.

Henesnarfel
sumber
Terima kasih, tapi saya ingin menghapus elemennya.
xyz
-1

Anda dapat membuat a Setdari larik dan kemudian membuat larik dari himpunan.

const array = [1, 1, 2, 3, 5, 5, 1];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // Result: [1, 2, 3, 5]
Mohib
sumber