ลบหลายองค์ประกอบออกจากอาร์เรย์ใน Javascript / jQuery


118

ฉันมีสองอาร์เรย์ อาร์เรย์แรกมีค่าบางค่าในขณะที่อาร์เรย์ที่สองมีดัชนีของค่าที่ควรลบออกจากอาร์เรย์แรก ตัวอย่างเช่น:

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จะแตกต่างกัน ฉันสามารถแก้ปัญหานี้ได้โดยใช้อาร์เรย์ชั่วคราวและคัดลอกค่าทั้งหมดไปยังอาร์เรย์ที่สอง แต่ฉันสงสัยว่ามีวิธีดั้งเดิมใดบ้างที่เราสามารถส่งผ่านหลายดัชนีเพื่อลบค่าออกจากอาร์เรย์ได้

ฉันต้องการโซลูชัน jQuery (ไม่แน่ใจว่าใช้grepที่นี่ได้ไหม)

คำตอบ:


256

มักจะมี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()โดยไม่ต้อง messing up ดัชนีของรายการที่ยังเพื่อจะออก

หมายเหตุข้างต้นฉันใช้ไวยากรณ์อาร์เรย์ - ตัวอักษรกับวงเล็บเหลี่ยมเพื่อประกาศอาร์เรย์ทั้งสอง นี่เป็นไวยากรณ์ที่แนะนำเนื่องจากการnew Array()ใช้งานอาจทำให้เกิดความสับสนเนื่องจากตอบสนองแตกต่างกันไปขึ้นอยู่กับจำนวนพารามิเตอร์ที่คุณส่งผ่าน

แก้ไข : เพิ่งเห็นความคิดเห็นของคุณเกี่ยวกับคำตอบอื่นเกี่ยวกับอาร์เรย์ของดัชนีที่ไม่จำเป็นต้องอยู่ในลำดับใด ๆ หากเป็นเช่นนั้นให้เรียงลำดับจากมากไปหาน้อยก่อนที่คุณจะเริ่ม:

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

และทำตามนั้นด้วย$.each()วิธีการวนซ้ำ / / ฯลฯ ที่คุณต้องการ


1
จะไม่ทำให้ดัชนีสับสน
มูฮัมหมัดอูเมอร์

5
@MuhammadUmer - ไม่ไม่ใช่ถ้าคุณทำถูกต้องซึ่งเป็นสิ่งที่คำตอบของฉันอธิบาย
nnnnnn

5
ขอบคุณสำหรับการรับรู้ลำดับย้อนกลับ
Daniel Nalbach

2
+1 ฉันไม่รู้ว่าฉันต้องทำการประกบในลำดับย้อนกลับแม้ว่าแทนที่จะใช้ forEach วิธีของฉันใช้$.each(rvm.reverse(), function(e, i ) {})
Luis Stanley Jovel

1
สิ่งนี้จะใช้งานได้removeValFromIndex ก็ต่อเมื่อเรียงลำดับจากน้อยไปมาก
Kunal Burangi

24

นี่คือสิ่งที่ฉันใช้เมื่อไม่ได้ใช้ lodash / ขีดล่าง:

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

วิธีแก้สวยหรู! ตอนแรกฉันคิดว่ามันจะไม่ได้ผลเพราะฉันคิดว่าทุกครั้งที่โทรsliceคุณจะต้องคำนวณดัชนีใหม่ที่จะลบออก (-1 บนIndexestoBeRemoved) แต่มันใช้งานได้จริง!
Renato Gama

2
ฉลาดมากเกินไป
Farzad YZ

11
วิธีนี้ใช้งานได้หากIndexesToBeRemovedมีการจัดเรียงอาร์เรย์จากน้อยไปมากเท่านั้น
xfg

ดัชนีเหล่านั้นจะถูกยกเลิกหลังจากการต่อครั้งแรก
shinzou

@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

ขอบคุณมาก! @TheVillageIdiot
ecorvo

jsfiddler - ข้อผิดพลาด 404 ขออภัยจริงๆ แต่ไม่มีหน้าดังกล่าว
เถ้า

18

ฉันขอแนะนำให้คุณใช้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;
})

ดัชนีภายในตัวกรอง ... ไม่เหมาะสม
Alvaro Joao

1
upvote เร็วกว่าวิธีประกบตามjsperf.com/remove-multiple/1
lionbigcat

ที่ดี! ตอนนี้ฉันสามารถนอนหลับได้ :)
Firmansyah

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

ข้อมูลอ้างอิง MDN อยู่ที่นี่


@ riship89 ซอลง
mate64

@Karna: fiddle is down
riship89

1
โปรดทราบว่าในขณะที่เขียน (มิถุนายน 2014) 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)เวลา :) ปัญหาเกี่ยวกับโซลูชันการต่อสายคือเนื่องจากการใช้อาร์เรย์พื้นฐานเป็นอาร์เรย์อย่างแท้จริงการ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คัดลอกทั้งหมดซึ่งเป็นกำลังสอง

โซลูชันการต่อสาย (สมมติว่า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

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

รหัสของคุณควรจะทำงานได้เร็วขึ้นถ้าคุณทำและใช้แทน removeValFromIndexSet()removeValFromIndex.hasincludes
Boris

5

โซลูชันที่เรียบง่ายและมีประสิทธิภาพ (ความซับซ้อนเชิงเส้น) โดยใช้ตัวกรองและชุด :

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

ข้อดีอย่างมากของการใช้งานนั้นคือการดำเนินการค้นหาชุด ( 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

คุณสามารถแก้ไขโค้ดของคุณโดยการแทนที่ด้วยremoveValFromIndex removeValFromIndex.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"]


มีการนำไปใช้ในขีดล่างอย่างไร ... ระวังหากเทียบเท่ากับ indexO ของภายในตัวกรอง ... ไม่เหมาะสมเลย ...
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]

ดัชนีภายในตัวกรอง ... ไม่เหมาะสม
Alvaro Joao

0

ดูเหมือนว่าสมัครอาจเป็นสิ่งที่คุณกำลังมองหา
บางทีสิ่งนี้จะได้ผล?

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.