Soru JavaScript'teki bir diziden belirli bir öğeyi nasıl kaldırırım?


Bir dizi tam sayı var ve kullanıyorum .push() ona eleman eklemek için yöntem.

Belirli bir öğeyi bir diziden kaldırmanın basit bir yolu var mı? Gibi bir şey eşdeğer array.remove(int);.

kullanmak zorundayım çekirdek JavaScript - yok hayır çerçevelere izin verilir.


6131
2018-04-23 22:17


Menşei


Desteğe ihtiyacınız varsa <IE9 (iç çekmek) sonra kontrol et bu so soru ilişkin indexOf IE'de. - Scotty.NET
(lodash) dizi = ['a', 'b', 'c']; _.pull (dizi, 'a') // dizi => ['b', 'c']; Ayrıca bakınız stackoverflow.com/questions/5767325/... - Chun Yang
filtre yöntemi istediğini yapabilirsin. - Salvador Dali
Silme kullanabilirsiniz ancak bu dizini yeniden değil, bu alanı 'undefined × 1' olarak ayarlayacaktır. Örneğin: var liste = [1,2,3,4,5,6] -> listeyi sil [1] -> [1, tanımsız × 1, 3, 4, 5, 6]. - DevWL
Burada iki önemli olasılığın bir performans kriteri: jsben.ch/#/b4Ume - EscapeNetscape


Cevaplar:


Bul index kaldırmak istediğiniz dizi öğesinin ardından o dizini splice.

Splice () yöntemi, bir dizinin içeriğini kaldırarak değiştirir   Mevcut elemanlar ve / veya yeni elemanlar ekleyerek.

var array = [2, 5, 9];
var index = array.indexOf(5);
if (index > -1) {
  array.splice(index, 1);
}
// array = [2, 9]

İkinci parametre splice Kaldırılacak öğe sayısıdır. Bunu not et splice diziyi yerinde değiştirir ve kaldırılmış öğeleri içeren yeni bir dizi döndürür.


Not: indexOf için tarayıcı desteği Limitli


8923
2018-04-23 22:23



@Peter, evet haklı olabilirsin. Bu makalede daha fazla şey açıklanmakta ve uyumsuz tarayıcılar için bir geçici çözüm bulunmaktadır: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/... - Tom Wadley
Tehlikeli! Dinamik değerlerle çalışıyorsanız (diziden dinamik değerler ekleyin ve kaldırın) ve dizide değer yoksa (dizin -1 olur), yukarıdaki kod dizinin son öğesini kaldıracaktır. - Adrian P.
@AlexandreWiechersVaz Elbette siparişi korur, eğer olmasaydı kesinlikle değersiz olurdu - TheZ
IE tarayıcı desteği sorununu kod ekleyerek aşabilirsiniz. burada verilen
@AdrianP. array.indexOf(testValue) boş dizide -1 olacaktır ve bunun için test ediyorsanız ekleme yapılmaz. Belki de cevap o zamandan beri değişti. - UpTheCreek


Nasıl bekliyorsun bilmiyorum array.remove(int) davranmak. İstediğini düşünebildiğim üç olasılık var.

Dizindeki bir öğenin bir dizini kaldırmak için i:

array.splice(i, 1);

Her elemanı değer ile kaldırmak istiyorsanız number diziden:

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

Eğer sadece indekste eleman yapmak istiyorsanız i artık yok, ancak diğer öğelerin dizinlerinin değişmesini istemiyorsunuz:

delete array[i];

896
2018-04-23 22:20



delete bir öğeden bir öğeyi kaldırmanın doğru yolu değil! - Felix Kling
@FelixKling Bu, bunu yapmak istediğinizde işe yarar. array.hasOwnProperty(i) döner false ve bu pozisyonda geri dönüş undefined. Ama bunu yapmak için çok yaygın bir şey olmadığını itiraf edeceğim. - Peter Olson
delete dizinin uzunluğunu güncellemez, ne gerçekten silme, sadece özel değerle değiştirir undefined. - diosney
@diosney Söylediğinizde ne demek istediğimi bilmiyorum, bu gerçekten öğeyi silmez. Dahası, bu endekste değeri basitçe değiştirmek yerine undefined: hem dizini hem de değeri diziden, yani delete array[0], "0" in array yanlış dönecektir. - Peter Olson
silinen özellikler ile uğraşıyorsanız silme iyi bir mekanizmadır var array=[];array['red']=1;array['green']=2;array['blue']=3;delete array['green']; - Jefferey Cave


2016 ekim tarihinde düzenlendi

  • Basit, sezgisel ve açık yapın (https://en.wikipedia.org/wiki/Occam%27s_razor)
  • Değişmez yapın (orijinal dizi değişmeden kalır)
  • Tarayıcınız bunları desteklemiyorsa standart JS işlevleriyle yapın - polyfill kullan

Bu kod örneğinde kullanıyorum "(...) Array.filter" İstenmeyen öğeleri diziden kaldırmak için işlev, bu işlev orijinal diziyi değiştirmez ve yeni bir tane oluşturur. Tarayıcınız bu işlevi desteklemiyorsa (ör. Sürüm 9'dan önceki IE veya Firefox'un 1.5 sürümünden önce), kullanmayı düşünün. Mozilla'dan filtre polyfill.

Kaldırma öğesi (ECMA-262 Edition 5 kodu aka oldstyle JS)

var value = 3

var arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(function(item) { 
    return item !== value
})

console.log(arr)
// [ 1, 2, 4, 5 ]

Öğe kaldırılıyor (ES2015 kodu)

let value = 3

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => item !== value)

console.log(arr)
// [ 1, 2, 4, 5 ]

ÖNEMLİ ES2015 "() => {}" ok işlevi sözdizimi IE'de hiç desteklenmiyor, 45 sürümünden önce Chrome, 22 sürümünden önce Firefox, 10 sürümden önce Safari. Eski tarayıcılarda ES2015 sözdizimini kullanmak için kullanabilirsiniz BabelJS


Birden çok öğeyi kaldırma (ES2016 kodu)

Bu yöntemin ek bir avantajı, birden fazla öğeyi kaldırabilmenizdir

let forDeletion = [2, 3, 5]

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => !forDeletion.includes(item))
// !!! Read below about array.includes(...) support !!!

console.log(arr)
// [ 1, 4 ]

ÖNEMLİ "array.includes (...)" işlevi IE'de hiç desteklenmiyor, 47'den önce Chrome, 43'ten önce Firefox, 9'dan önceki Safari ve 14'ten önce Edge Burada Mozilla'dan polyfill

Birden fazla öğeyi kaldırma (Son teknoloji deneysel JavaScript ES2018?)

// array-lib.js

export function remove(...forDeletion) {
    return this.filter(item => !forDeletion.includes(item))
}

// main.js

import { remove } from './array-lib.js'

let arr = [1, 2, 3, 4, 5, 3]

// :: This-Binding Syntax Proposal
// using "remove" function as "virtual method"
// without extending Array.prototype
arr = arr::remove(2, 3, 5)

console.log(arr)
// [ 1, 4 ]

Kendinizi BabelJS'de deneyin :)

Referans


678
2017-12-19 19:54



ama bazen, orijinal diziden (değişmez), örneğin Angular 2 * ngFor direktifinde kullanılan diziyi kaldırmak istiyoruz - Ravinder Payal
Kabul edilen çözümden daha iyidir çünkü bir eşleşme ve değişmezliğin tek bir oluşumunu varsaymaz. - Greg
Filtre kullanmak, splice kullanmaktan çok daha hoştur. Çok basit. - user3344977
filter büyük bir dizi için çok daha yavaş olmalı mı? - Nathan
Süper yavaş yöntem. - highmaintenance


Boş bir nokta tutmak isteyip istemediğinize bağlıdır.

Boş bir yuva istiyorsanız, silmek iyidir:

delete array[ index ];

Eğer yapmazsan, ek yeri yöntem:

array.splice( index, 1 );

Ve bu öğenin değerine ihtiyacınız varsa, sadece döndürülen dizinin öğesini saklayabilirsiniz:

var value = array.splice( index, 1 )[0];

Bunu bir sırayla yapmak isterseniz, kullanabilirsiniz array.pop() sonuncusu için array.shift() İlk için (ve her ikisi de öğenin değerini döndürür).

Ve öğenin dizinini bilmiyorsanız, kullanabilirsiniz array.indexOf( item ) onu almak için if() bir öğe almak veya bir while() hepsini almak için). array.indexOf( item ) bulunamadıysa dizin veya -1 değerini döndürür.


359
2018-04-23 22:32



Farketmeye değer var valuekaldırılan değeri değil, kaldırılan değeri içeren bir diziyi saklar. - Jakub
delete bir öğe bir diziden kaldırmak için doğru yol değildir! - Progo
"Boş bir alan açmak" istiyorsanız array[index] = undefined;. kullanma delete optimizasyonu yok edecektir. - Bergi
@Jakub çok iyi yorum çünkü çok zaman kaybettiğimi ve uygulama kodumun bir şekilde kırıldığını düşündüğümü anlamak için ... - Pascal


Bir arkadaş sorunları yaşıyordu Internet Explorer 8ve bana ne yaptığını gösterdi. Ona yanlış olduğunu söyledim ve bana cevabın burada olduğunu söyledi. Geçerli üstteki yanıt tüm tarayıcılarda (örneğin Internet Explorer 8) çalışmayacaktır ve yalnızca öğenin ilk oluşumunu kaldırır.

Bir diziden TÜM örnekleri kaldır

function remove(arr, item) {
    for (var i = arr.length; i--;) {
        if (arr[i] === item) {
            arr.splice(i, 1);
        }
    }
}

Diziyi geriye doğru çevirir (indeksler ve uzunluk, öğeler kaldırıldıkça değişeceğinden) ve bulunursa öğeyi kaldırır. Tüm tarayıcılarda çalışır.


228
2017-08-10 19:21



Döngüler, döngü başlangıcından beri olmamalıdır i = arr.length -1 veya i-- max indeksi ile aynı yapmak. arr.length sadece başlangıç ​​değeri i. i-- hep olacak truthy (ve her döngüde 1 ile azaltma) eşit olana kadar 0 (bir falsi değeri) ve döngü durur. - gabeno
İkinci işlev oldukça verimsizdir. Her yinelemede "indexOf", dizinin başlangıcından itibaren aramaya başlar. - Ujeenator
@AmberdeBlack, 1'den fazla meydana gelen bir koleksiyon üzerinde madde, aramak daha iyi filtre bunun yerine yöntem arr.filter(function (el) { return el !== item })diziyi birçok kez mutasyona uğratmaktan kaçınmak. Bu biraz daha fazla bellek tüketir, ancak daha az iş yapılması gerektiğinden çok daha verimli çalışır. - Eugene Kuzmenko
@AlJey, sadece IE9 + 'dan kullanılabilir. Hala işe yaramayacağı bir şans var. - Ujeenator
Bu cevap benim için çalıştı çünkü bazı öğeleri çıkarmam gerekti, ancak belirli bir sıraya ihtiyacım yoktu. For döngüsünün geriye doğru ilerlemesi, öğeleri diziden mükemmel şekilde kaldırmayı sağlar. - mintedsky


İki önemli yaklaşım vardır:

  1. ) (Splice: anArray.splice(index, 1);

  2. silmek: delete anArray[index];

Bir dizi için silme kullandığınızda dikkatli olun. Nesnelerin niteliklerini silmek için iyi ama diziler için çok iyi değil. Kullanmak daha iyidir splice diziler için.

Kullandığınızda unutmayın delete bir dizi için yanlış sonuçlar alabilirsiniz anArray.length. Diğer bir deyişle, delete öğeyi kaldırır ancak uzunluk özelliğinin değerini güncellemez.

Ayrıca, silme kullanımından sonra indeks numaralarında delikler olmasını bekleyebilirsiniz. 1,3,4,8,9,11 indeksleri ve silme kullanmadan önceki uzunluğa sahip olursunuz. Bu durumda, tüm indeksli for dizinler artık sıralı olmadığından döngüler çökecektir.

Kullanmak zorundaysanız delete nedense kullanmalısın for each diziler arasında döngü gerektiğinde döngüler. Aslına bakarsanız, mümkünse her zaman döngüler için indeksli kullanmaktan kaçının. Bu şekilde kod daha sağlam ve endekslerle ilgili problemlere daha az eğilimli olacaktır.


131
2017-12-21 11:32





Array.prototype.remByVal = function(val) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] === val) {
            this.splice(i, 1);
            i--;
        }
    }
    return this;
}
//Call like
[1, 2, 3, 4].remByVal(3);

Array.prototype.remByVal = function(val) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] === val) {
            this.splice(i, 1);
            i--;
        }
    }
    return this;
}

var rooms = ['hello', 'something']

rooms = rooms.remByVal('hello')

console.log(rooms)


104
2018-04-23 22:20



Bu yaklaşımın büyük bir hayranı değilim. Farklı kütüphaneler veya çerçeveler kullanarak sonuçlanırsanız, birbirleriyle çelişki kurabilirler. - Charlie Kilian
Bu da çalıştı, sonunda indexOf fonksiyonu ile gitmeyi seçtim. Yardım için teşekkürler! - Walker
Kötü fikir, şu yazıya bakın: stackoverflow.com/questions/948358/array-prototype-problem - MMeah
Eğer yapıyorsan for in bir dizide zaten bir probleminiz var. - Zirak
yaparsan for in dizilerde zaten büyük sorunlarınız var. - Rainb


Kullanmaya gerek yok indexOf veya splice. Bununla birlikte, yalnızca bir öğenin bir oluşumunu kaldırmak istiyorsanız daha iyi performans gösterir.

Bul ve taşı (hareket et):

function move(arr, val) {
  var j = 0;
  for (var i = 0, l = arr.length; i < l; i++) {
    if (arr[i] !== val) {
      arr[j++] = arr[i];
    }
  }
  arr.length = j;
}

kullanım indexOf ve splice (indeksi):

function indexof(arr, val) {
  var i;
  while ((i = arr.indexOf(val)) != -1) {
    arr.splice(i, 1);
  }
}

Sadece kullan splice (Uç uca ekleme):

function splice(arr, val) {
  for (var i = arr.length; i--;) {
    if (arr[i] === val) {
      arr.splice(i, 1);
    }
  }
}

1000 elemanlı dizi için nodejs üzerinde çalışma zamanları (10000'den fazla çalışma):

indeksi yaklaşık 10x daha yavaş hareket. Çağrıyı kaldırarak geliştirilmiş olsa bile indexOf içinde ek yeri çok daha kötü performans gösteriyor hareket.

Remove all occurrences:
    move 0.0048 ms
    indexof 0.0463 ms
    splice 0.0359 ms

Remove first occurrence:
    move_one 0.0041 ms
    indexof_one 0.0021 ms

82
2017-09-19 01:53



Burada sunulan 'taşıma' yönteminin tüm tarayıcılarda çalışması gerektiği gibi görünüyor ve ayrıca ekstra bir dizi oluşturulmasını önler; Buradaki diğer çözümlerin çoğu, bu sorunlardan birini veya her ikisini de içerir. Bence bu "güzel" görünmese bile çok daha fazla oy hak ediyor. - sockmonk


Cevap vermek için çok yaşlı, ancak bir değer yerine bir yüklem sağlayan birisine yardımcı olabilir.

NOT: verilen diziyi günceller ve etkilenen satırları döndürür

kullanım

var removed = helper.removeOne(arr, row => row.id === 5 );

var removed = helper.remove(arr, row => row.name.startsWith('BMW'));

Tanım

var helper = {

    // Remove and return the first occurrence     

    removeOne: function(array, predicate) {
        for (var i = 0; i < array.length; i++) {
            if (predicate(array[i])) {
                return array.splice(i, 1);
            }
        }
    },

    // Remove and return all occurrences  

    remove: function(array, predicate) {
        var removed = [];

        for (var i = 0; i < array.length;) {

            if (predicate(array[i])) {
                removed.push(array.splice(i, 1));
                continue;
            }

            i++;                
        }

        return removed;
    }
};

56
2018-05-02 12:00



-1 kontrolüne ihtiyacınız olduğunu bilmiyorum (i> -1). Ayrıca, bence bu işlevler, filtreden daha çok filtre gibi davranıyor. Eğer row.id === 5 'i geçerseniz, bu sadece id 5 ile bir dizi ile sonuçlanacak, bu yüzden kaldırmanın tersini yapıyor. ES2015'te güzel görünür: var result = ArrayHelper.remove (myArray, row => row.id === 5); - What Would Be Cool
@WhatWouldBeCool bu işlev orijinal diziyi değiştirir ve sonucu yeni bir diziye kopyalamak yerine kaldırılan öğeyi döndürür - amd


John Resig iyi bir uygulama yayınladı:

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

Genel bir nesneyi genişletmek istemiyorsanız, bunun yerine aşağıdaki gibi bir şey yapabilirsiniz:

// Array Remove - By John Resig (MIT Licensed)
Array.remove = function(array, from, to) {
    var rest = array.slice((to || from) + 1 || array.length);
    array.length = from < 0 ? array.length + from : from;
    return array.push.apply(array, rest);
};

Ancak bunu yayınlamamın temel nedeni, kullanıcıları bu sayfadaki yorumlarda önerilen alternatif uygulamaya karşı uyarmaktır (14 Aralık 2007):

Array.prototype.remove = function(from, to){
  this.splice(from, (to=[0,from||1,++to-from][arguments.length])<0?this.length+to:to);
  return this.length;
};

İlk başta gayet iyi çalışıyor gibi görünüyor, ama acı verici bir süreç boyunca, bir dizideki ikinci son öğeyi kaldırmaya çalışırken başarısız olduğunu keşfettim. Örneğin, 10 öğeli bir diziniz varsa ve bu öğeyle 9. öğeyi kaldırmayı denerseniz:

myArray.remove(8);

8 elementli bir dizi ile sonuçlanırsınız. Neden olduğunu bilmiyorum ama John'un orijinal uygulamasının bu problemi olmadığını doğruladım.


53
2017-08-30 19:07



Sadece zor yoldan öğrenmenin neden iyi bir fikir olduğunu Object.prototype.hasOwnProperty her zaman ¬¬ - Davi Fiamenghi