Javascript / jQuery의 배열에서 여러 요소 제거


117

두 개의 배열이 있습니다. 첫 번째 배열에는 일부 값이 포함되고 두 번째 배열에는 첫 번째 배열에서 제거되어야하는 값의 인덱스가 포함됩니다. 예를 들면 :

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()아직 - 투 - 제거 할 항목의 인덱스를 엉망으로하지 않고.

위의 내용에서 대괄호가있는 array-literal 구문을 사용하여 두 배열을 선언했습니다. new Array()전달하는 매개 변수 수에 따라 다르게 응답 하므로 사용이 잠재적으로 혼란 스럽기 때문에 권장되는 구문 입니다.

편집 : 특정 순서가 아닌 인덱스 배열에 대한 다른 답변에 대한 귀하의 의견을 보았습니다. 이 경우 시작하기 전에 내림차순으로 정렬하십시오.

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

그리고 $.each()당신이 좋아 하는 루핑 / / 등 방법으로 그것을 따르십시오 .


1
인덱스까지 늘 슬라이스 엉망
무하마드 Umer

5
@MuhammadUmer-아니요, 올바르게 수행하면 내 대답이 설명하는 것입니다.
nnnnnn

5
역순 인식에 감사드립니다.
Daniel Nalbach

2
+1, 나는 스플 라이스를 역순으로해야한다는 것을 깨닫지 못했지만 forEach를 사용하는 대신 내 접근 방식은 다음을 사용하고 있습니다$.each(rvm.reverse(), function(e, i ) {})
Luis Stanley Jovel

1
removeValFromIndex 오름차순으로 정렬 된 경우에만 작동합니다
Kunal Burangi

24

다음은 lodash / underscore를 사용하지 않을 때 사용하는 것입니다.

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

우아한 솔루션! 처음에는 안될 줄 알았는데 전화 할 때마다slice 할 제거 할 인덱스 (-1 on IndexestoBeRemoved) 를 다시 계산해야 했지만 실제로 작동합니다!
Renato Gama

2
너무 영리함
영리함

11
이 솔루션은 IndexesToBeRemoved배열 만 오름차순으로 정렬 된 경우에 작동합니다 .
xfg

이러한 인덱스는 첫 번째 스플 라이스 이후에 무효화됩니다.
신조

@shinzou- IndexesToBeRemoved정렬 된 경우 (오름차순) 아님.
nnnnnn

18

아닙니다 .의 및 기능을 in-place사용하여 수행 할 수 있습니다 .grepinArrayjQuery

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

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

바이올린을 확인 하십시오 .


방금 말씀하신다면 제자리에 (충분히 가까움)valuesArr = $.grep(...);
nnnnnn

1
@nnnnnn ha ha ha 회의를 위해 떠나고 있었으므로 (당신은 그들이 당신을 그렇게 생산적으로 만든다는 것을 알고 있습니다) 많은 실험을하지 않았습니다.
TheVillageIdiot 2012

1
@ cept0 왜 반대표를해야합니까? OP는 jQuery 솔루션을 요청했습니다.
Ste77

정말 고맙습니다! @TheVillageIdiot
ecorvo

jsfiddler-오류 404입니다. 정말 죄송합니다. 그런 페이지가 없습니다.
Ash


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

MDN 참조는 여기


@ riship89 바이올린이 다운되었습니다
mate64

@Karna : 바이올린이 다운되었습니다
riship89 2014-06-04

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)시간 과 함께 답변을 게시 할 필요가 있다고 느낍니다 :). 스플 라이스 솔루션의 문제점은 배열의 기본 구현이 문자 그대로 배열이기 때문에 각 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

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.has대신 includes.
Boris

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

이 구현의 가장 큰 장점은 예를 들어 설정 조회 작업 ( has함수)이 nevace의 답변보다 더 빠른 일정한 시간이 걸린다는 것입니다.


:) 기꺼이 도와 @MichaelPaccione
알베르토 트린 다데 타바레스

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의 내부에 해당 있다면 ... 모두에서 최적하지 ...주의
알바 주앙

1

필터 + indexOf (IE9 +) :

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

또는 ES6 필터 + 찾기 (Edge +) :

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

필터의 내부 ... 최적되지 같이 IndexOf
알바 주앙

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 2012

-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.