Làm thế nào tôi có thể loại bỏ một mục cụ thể từ một mảng?


8295

Tôi có một dãy số và tôi đang sử dụng .push()phương thức để thêm các phần tử vào nó.

Có một cách đơn giản để loại bỏ một yếu tố cụ thể khỏi một mảng?

Tôi đang tìm kiếm tương đương với một cái gì đó như:

array.remove(number);

Tôi phải sử dụng JavaScript cốt lõi . Khung không được phép.

Câu trả lời:


11891

Tìm indexphần tử mảng mà bạn muốn loại bỏ bằng cách sử dụng indexOfvà sau đó xóa chỉ mục đó bằng splice.

Phương thức splice () thay đổi nội dung của một mảng bằng cách loại bỏ các phần tử hiện có và / hoặc thêm các phần tử mới.

const array = [2, 5, 9];

console.log(array);

const index = array.indexOf(5);
if (index > -1) {
  array.splice(index, 1);
}

// array = [2, 9]
console.log(array); 

Tham số thứ hai splicelà số lượng phần tử cần loại bỏ. Lưu ý rằng splicesửa đổi mảng tại chỗ và trả về một mảng mới có chứa các phần tử đã bị xóa.


Vì lý do đầy đủ, đây là các chức năng. Hàm thứ nhất chỉ loại bỏ sự xuất hiện duy nhất (nghĩa là loại bỏ kết quả khớp đầu tiên 5từ [2,5,9,1,5,8,5]), trong khi chức năng thứ hai loại bỏ tất cả các lần xuất hiện:

function removeItemOnce(arr, value) { 
    var index = arr.indexOf(value);
    if (index > -1) {
        arr.splice(index, 1);
    }
    return arr;
}

function removeItemAll(arr, value) {
    var i = 0;
    while (i < arr.length) {
        if(arr[i] === value) {
            arr.splice(i, 1);
        } else {
            ++i;
        }
    }
    return arr;
}

15
@Peter, vâng bạn có thể đúng. Bài viết này giải thích thêm và có một cách giải quyết cho các trình duyệt không tương thích: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/
Kẻ

33
@AlexandreWiechersVaz Tất nhiên là nó giữ được trật tự, nếu không thì nó sẽ hoàn toàn vô giá trị
TheZ

15
Bạn có thể khắc phục sự cố hỗ trợ trình duyệt IE bằng cách bao gồm mã được cung cấp tại đây

15
@AdrianP. array.indexOf(testValue)trên mảng trống sẽ là -1 và nếu bạn đang kiểm tra thì không có mối nối nào. Có lẽ câu trả lời đã thay đổi kể từ đó.
UpTheCux

13
IE 7, IE8, IE9, IE10 không được Microsoft hỗ trợ, tại sao các nhà phát triển web nên hỗ trợ các trình duyệt cũ đó? Chỉ cần hiển thị thông báo về việc nâng cấp trình duyệt! support.microsoft.com/en-us/lifecycle/ khăn
Lukas Liesis

1268

Tôi không biết bạn đang mong đợi array.remove(int)cư xử thế nào. Có ba khả năng tôi có thể nghĩ rằng bạn có thể muốn.

Để loại bỏ một phần tử của một mảng tại một chỉ mục i:

array.splice(i, 1);

Nếu bạn muốn xóa mọi phần tử có giá trị numberkhỏi mảng:

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

Nếu bạn chỉ muốn làm cho phần tử tại chỉ mục ikhông còn tồn tại, nhưng bạn không muốn các chỉ mục của các phần tử khác thay đổi:

delete array[i];

334
deletekhông phải là cách chính xác để loại bỏ một phần tử khỏi một mảng!
Felix Kling

71
@FelixKling Nó phụ thuộc, nó hoạt động nếu bạn muốn làm cho nó array.hasOwnProperty(i)trở lại falsevà có phần tử ở vị trí đó trả về undefined. Nhưng tôi sẽ thừa nhận rằng đó không phải là điều rất phổ biến muốn làm.
Peter Olson

88
deletesẽ không cập nhật độ dài của mảng cũng không thực sự xóa phần tử, chỉ thay thế nó bằng giá trị đặc biệt undefined.
diosney

34
@diosney Tôi không hiểu ý của bạn khi bạn nói nó không thực sự xóa phần tử. Hơn nữa, nó không chỉ đơn giản là thay thế giá trị tại chỉ mục đó bằng undefined: nó loại bỏ cả chỉ mục và giá trị khỏi mảng, tức là sau đó delete array[0], "0" in arraysẽ trả về false.
Peter Olson

17
@GrantGryczan Xin lỗi, tôi không đồng ý. Tôi không thấy sự cần thiết phải loại bỏ điều này. Văn bản trên giải thích rõ ràng những gì nó làm và nó giúp những người không biết những gì deletecần hiểu tại sao nó không hoạt động như họ mong đợi.
Peter Olson

1205

Chỉnh sửa vào tháng 10 năm 2016

  • Làm điều đó đơn giản, trực quan và rõ ràng ( dao cạo của Occam )
  • Làm điều đó bất biến (mảng ban đầu không thay đổi)
  • Làm điều đó với các hàm JavaScript tiêu chuẩn, nếu trình duyệt của bạn không hỗ trợ chúng - hãy sử dụng polyfill

Trong ví dụ mã này, tôi sử dụng hàm "Array.filter (...)" để loại bỏ các mục không mong muốn khỏi một mảng. Hàm này không thay đổi mảng ban đầu và tạo một mảng mới. Nếu trình duyệt của bạn không hỗ trợ chức năng này (ví dụ: Internet Explorer trước phiên bản 9 hoặc Firefox trước phiên bản 1.5), hãy xem xét sử dụng bộ lọc polyfill từ Mozilla .

Xóa mục (mã ECMA-262 Phiên bản 5 hay còn gọi là JavaScript kiểu cũ)

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 ]

Xóa mục (mã ECMAScript 6)

let value = 3

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

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

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

Cú pháp hàm mũi tên QUAN TRỌNG ECMAScript 6 "() => {}" hoàn toàn không được hỗ trợ trong Internet Explorer, Chrome trước phiên bản 45, Firefox trước 22 phiên bản và Safari trước 10 phiên bản. Để sử dụng cú pháp ECMAScript 6 trong các trình duyệt cũ, bạn có thể sử dụng BabelJS .


Xóa nhiều mục (mã ECMAScript 7)

Một lợi thế bổ sung của phương pháp này là bạn có thể loại bỏ nhiều mục

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 ]

Chức năng "Array.includes (...)" QUAN TRỌNG hoàn toàn không được hỗ trợ trong Internet Explorer, Chrome trước phiên bản 47, Firefox trước phiên bản 43, Safari trước phiên bản 9 và Edge trước phiên bản 14 vì vậy đây là polyfill từ Mozilla .

Loại bỏ nhiều mục (trong tương lai, có thể)

Nếu đề xuất "Cú pháp liên kết này" được chấp nhận, bạn sẽ có thể thực hiện việc này:

// 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 ]

Hãy thử nó trong BabelJS :)

Tài liệu tham khảo


6
nhưng, đôi khi chúng tôi muốn xóa phần tử khỏi mảng ban đầu (không bất biến), ví dụ mảng được sử dụng trong chỉ thị Angular 2 * ngFor
Ravinder Payal

43
Tốt hơn so với giải pháp được chấp nhận vì nó không giả sử chỉ có một lần xuất hiện của trận đấu và tốt nhất là bất biến
Greg

13
filterphải chậm hơn nhiều cho một mảng lớn mặc dù?
Nathan

3
Điểm bất biến được đề cập là gì nếu bạn sử dụng gán cùng một biến trong ví dụ của mình? :)
mench

12
Đây là một câu trả lời tuyệt vời. Splice là một chức năng chuyên biệt để đột biến không lọc. filtercó thể có hiệu suất chậm hơn nhưng nó an toàn hơn và mã tốt hơn. Ngoài ra, bạn có thể lọc theo chỉ mục bằng cách chỉ định đối số thứ hai trong lambda:arr.filter((x,i)=>i!==2)
Matthew

449

Nó phụ thuộc vào việc bạn có muốn giữ một chỗ trống hay không.

Nếu bạn muốn có một chỗ trống, hãy xóa đi:

delete array[index];

Nếu bạn không, bạn nên sử dụng phương pháp mối nối :

array.splice(index, 1);

Và nếu bạn cần giá trị của mục đó, bạn chỉ có thể lưu trữ phần tử của mảng được trả về:

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

Trong trường hợp bạn muốn thực hiện theo thứ tự nào đó, bạn có thể sử dụng array.pop()cho cái cuối cùng hoặc array.shift()cho cái đầu tiên (và cả hai đều trả về giá trị của vật phẩm).

Và nếu bạn không biết chỉ số của mặt hàng, bạn có thể sử dụng array.indexOf(item)để lấy nó (trong một if()để có được một mặt hàng hoặc trong một while()để có được tất cả chúng). array.indexOf(item)trả về chỉ số hoặc -1 nếu không tìm thấy. 


25
deletekhông phải là cách chính xác để loại bỏ một phần tử khỏi một mảng !!
Progo

16
Nếu bạn muốn "làm trống một khe", hãy sử dụng array[index] = undefined;. Sử dụng deletesẽ phá hủy tối ưu hóa.
Bergi

4
@Jakub nhận xét rất tốt vì để hiểu rằng tôi đã mất nhiều thời gian và nghĩ rằng mã ứng dụng của mình bị hỏng theo cách nào đó ...
Pascal

Đoạn cuối với lời giải thích về những gì bạn nhận được từ indexOf thực sự hữu ích
A. D'Alfonso

277

Một người bạn đã gặp vấn đề trong Internet Explorer 8 và cho tôi thấy những gì anh ta đã làm. Tôi nói với anh ấy là sai, và anh ấy nói với tôi rằng anh ấy đã có câu trả lời ở đây. Câu trả lời hàng đầu hiện tại sẽ không hoạt động trong tất cả các trình duyệt (ví dụ Internet Explorer 8) và nó sẽ chỉ xóa lần xuất hiện đầu tiên của mục.

Xóa TẤT CẢ các trường hợp khỏi một mảng

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

Nó lặp qua mảng ngược (vì các chỉ số và độ dài sẽ thay đổi khi các mục bị xóa) và xóa mục nếu tìm thấy. Nó hoạt động trong tất cả các trình duyệt.


11
@sroes không nên vì vòng lặp bắt đầu tại i = arr.length -1hoặc i--làm cho nó giống như chỉ mục tối đa. arr.lengthchỉ là một giá trị ban đầu cho i. i--sẽ luôn luôn được truthy (và giảm 1 tại mỗi op loop) cho đến khi nó bằng 0(một giá trị falsy) và vòng lặp sau đó sẽ dừng lại.
gmajivu

1
Chức năng thứ hai là không hiệu quả. Trên mỗi lần lặp "indexOf" sẽ bắt đầu tìm kiếm từ đầu mảng.
ujeenator

3
@AmberdeBlack, trên một bộ sưu tập có hơn 1 lần xuất hiện của mặt hàng , tốt hơn hết là gọi phương thức bộ lọc thay vào đó arr.filter(function (el) { return el !== item }), tránh việc phải thay đổi mảng nhiều lần. Điều này tiêu thụ bộ nhớ nhiều hơn một chút, nhưng hoạt động hiệu quả hơn nhiều, vì có ít việc cần phải hoàn thành.
Eugene Kuzmenko

1
@AlJey, nó chỉ có sẵn từ IE9 +. Vẫn còn cơ hội là nó sẽ không hoạt động.
ujeenator 30/03/2015

1
Câu trả lời này có hiệu quả với tôi vì tôi cần loại bỏ một số mặt hàng nhưng không theo thứ tự cụ thể nào. Tiến trình ngược của vòng lặp for ở đây xử lý loại bỏ các mục khỏi mảng một cách hoàn hảo.
mintedsky

172

Có hai cách tiếp cận chính:

  1. mối nối () :anArray.splice(index, 1);

  2. xóa :delete anArray[index];

Hãy cẩn thận khi bạn sử dụng xóa cho một mảng. Nó là tốt để xóa các thuộc tính của các đối tượng, nhưng không tốt cho mảng. Nó là tốt hơn để sử dụngsplice cho các mảng.

Hãy nhớ rằng khi bạn sử dụng deletecho một mảng, bạn có thể nhận được kết quả sai anArray.length. Nói cách khác,delete sẽ loại bỏ phần tử, nhưng nó sẽ không cập nhật giá trị của thuộc tính độ dài.

Bạn cũng có thể có lỗ hổng trong số chỉ mục sau khi sử dụng xóa, ví dụ: bạn có thể có các chỉ số 1, 3, 4, 8, 9 và 11 và độ dài như trước khi sử dụng xóa. Trong trường hợp đó, tất cả forcác vòng lặp được lập chỉ mục sẽ sụp đổ, vì các chỉ mục không còn tuần tự.

Nếu bạn buộc phải sử dụng deletevì một số lý do, thì bạn nên sử dụng for eachcác vòng lặp khi bạn cần lặp qua các mảng. Vì thực tế, luôn luôn tránh sử dụng forcác vòng lặp được lập chỉ mục , nếu có thể. Bằng cách đó, mã sẽ mạnh mẽ hơn và ít gặp vấn đề với các chỉ mục.


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


14
Tôi không phải là một fan hâm mộ lớn của phương pháp này. Nếu bạn kết thúc bằng cách sử dụng các thư viện hoặc khung khác nhau, chúng có thể sẽ xung đột với nhau.
Charlie Kilian

10
Ý tưởng tồi, xem bài đăng này: stackoverflow.com/questions/94858/array-prototype-pro
Hiệu

10
Nếu bạn đang thực hiện một for inmảng, bạn đã có một vấn đề.
Zirak

2
nếu bạn làm for intrên mảng, bạn đã có vấn đề lớn hơn.
Rainb

sử dụng Object.defineProperty stackoverflow.com/a/35518127/3779853 và bạn vẫn ổn.
phil294

105

Không có nhu cầu sử dụng indexOfhoặcsplice . Tuy nhiên, nó hoạt động tốt hơn nếu bạn chỉ muốn loại bỏ một lần xuất hiện của một phần tử.

Tìm và di chuyển (di chuyển):

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

Sử dụng indexOfsplice(indexof):

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

Chỉ sử dụng splice(mối nối):

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

Thời gian chạy trên nodejs cho mảng có 1000 phần tử (trung bình hơn 10000 lần chạy):

indexof chậm hơn khoảng 10 lần so với di chuyển . Ngay cả khi được cải thiện bằng cách loại bỏ lệnh gọi đến indexOftrong mối nối, nó vẫn hoạt động kém hơn nhiều so với di chuyển .

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

5
Có vẻ như phương pháp 'di chuyển' được trình bày ở đây sẽ hoạt động trong tất cả các trình duyệt và cũng tránh tạo ra một mảng bổ sung; hầu hết các giải pháp khác ở đây có một hoặc cả hai vấn đề này. Tôi nghĩ rằng cái này xứng đáng được nhiều phiếu hơn, ngay cả khi nó không có vẻ "đẹp".
sockmonk

73

Điều này cung cấp một vị ngữ thay vì một giá trị.

LƯU Ý: nó sẽ cập nhật mảng đã cho và trả về các hàng bị ảnh hưởng.

Sử dụng

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

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

Định nghĩa

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

Tôi không biết rằng bạn cần kiểm tra -1 (i> -1). Ngoài ra, tôi nghĩ rằng các chức năng này hoạt động giống như bộ lọc hơn là loại bỏ. Nếu bạn vượt qua row.id === 5, nó sẽ dẫn đến một mảng chỉ có id 5, vì vậy nó đang làm ngược lại với remove. Nó sẽ trông đẹp trong ES2015: var result = ArrayHelper.remove (myArray, row => row.id === 5);
Điều gì sẽ tuyệt vời vào

@WhatWouldBeCool chức năng này sửa đổi mảng ban đầu và trả về mục đã xóa thay vì sao chép kết quả sang một mảng mới
amd

68

Bạn có thể làm điều đó dễ dàng với phương thức lọc :

function remove(arrOriginal, elementToRemove){
    return arrOriginal.filter(function(el){return el !== elementToRemove});
}
console.log(remove([1, 2, 1, 0, 3, 1, 4], 1));

Điều này loại bỏ tất cả các yếu tố khỏi mảng và cũng hoạt động nhanh hơn so với sự kết hợp của sliceindexOf.


3
Bạn có một nguồn trên đó là nhanh hơn?
dùng3711421

2
Giải pháp tốt đẹp. Nhưng như bạn chỉ ra, nhưng điều quan trọng là tạo hói, nó không tạo ra kết quả tương tự như lát cắt và indexOf vì nó sẽ xóa tất cả các lần xuất hiện của 1
user3711421

1
@ user3711421 điều này là do chỉ cắt lát và indexOf không làm những gì anh ta muốn "để loại bỏ một yếu tố cụ thể". Nó chỉ xóa phần tử một lần, phần này loại bỏ phần tử cụ thể cho dù bạn có bao nhiêu phần tử trong số đó
Salvador Dali

66

John Resig đăng một triển khai tốt :

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

Nếu bạn không muốn mở rộng một đối tượng toàn cầu, thay vào đó, bạn có thể làm một cái gì đó như sau:

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

Nhưng lý do chính tôi đăng bài này là để cảnh báo người dùng chống lại việc triển khai thay thế được đề xuất trong các nhận xét trên trang đó (ngày 14 tháng 12 năm 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;
};

Nó có vẻ hoạt động tốt lúc đầu, nhưng qua một quá trình đau đớn, tôi phát hiện ra nó thất bại khi cố gắng loại bỏ phần tử thứ hai đến phần cuối trong một mảng. Ví dụ: nếu bạn có mảng 10 phần tử và bạn cố gắng loại bỏ phần tử thứ 9 bằng phần này:

myArray.remove(8);

Bạn kết thúc với một mảng 8 phần tử. Không biết tại sao nhưng tôi xác nhận việc triển khai ban đầu của John không có vấn đề này.


Chỉ cần học theo cách khó tại sao nên sử dụng Object.prototype.hasOwnPropertyluôn ¬¬
Davi Fiamenghi

64

Underscore.js có thể được sử dụng để giải quyết các vấn đề với nhiều trình duyệt. Nó sử dụng các phương thức trình duyệt trong xây dựng nếu có. Nếu chúng vắng mặt như trong trường hợp các phiên bản Internet Explorer cũ hơn, nó sử dụng các phương thức tùy chỉnh của riêng nó.

Một ví dụ đơn giản để xóa các thành phần khỏi mảng (khỏi trang web):

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1); // => [2, 3, 4]

Mặc dù thanh lịch và súc tích, OP chỉ đề cập rõ ràng về cốt lõi của JS
EigenFool

64

Bạn có thể sử dụng ES6. Ví dụ: để xóa giá trị '3' trong trường hợp này:

var array=['1','2','3','4','5','6']
var newArray = array.filter((value)=>value!='3');
console.log(newArray);

Đầu ra:

["1", "2", "4", "5", "6"]

4
Câu trả lời này là tốt bởi vì nó tạo ra một bản sao của mảng ban đầu, thay vì trực tiếp sửa đổi bản gốc.
Claudio Holanda

Lưu ý: Array.prototype.filter là ECMAScript 5.1 (Không có IE8). để biết các giải pháp cụ thể hơn: stackoverflow.com/a/54390552/8958729
Chang

54

Nếu bạn muốn một mảng mới với các vị trí bị xóa, bạn luôn có thể xóa phần tử cụ thể và lọc ra mảng. Có thể cần một phần mở rộng của đối tượng mảng cho các trình duyệt không triển khai phương thức lọc, nhưng về lâu dài sẽ dễ dàng hơn vì tất cả những gì bạn làm là:

var my_array = [1, 2, 3, 4, 5, 6];
delete my_array[4];
console.log(my_array.filter(function(a){return typeof a !== 'undefined';}));

Nó sẽ hiển thị [1, 2, 3, 4, 6].


45

Kiểm tra mã này. Nó hoạt động trong mọi trình duyệt chính .

remove_item = function (arr, value) {
    var b = '';
    for (b in arr) {
        if (arr[b] === value) {
            arr.splice(b, 1);
            break;
        }
    }
    return arr;
}

Gọi chức năng này

remove_item(array,value);

4
@RolandIllig Ngoại trừ việc sử dụng một for in-loop và thực tế là tập lệnh có thể dừng trước đó, bằng cách trả lại kết quả từ vòng lặp trực tiếp. Các upvote là hợp lý;)
yckart 30/12/14

1
Đây là một cách tiếp cận tuyệt vời cho các mảng nhỏ. Nó hoạt động trong mọi trình duyệt, sử dụng mã tối thiểu và trực quan và không có bất kỳ khung, miếng chêm hoặc polyfill phức tạp nào khác.
Beejor

Tôi cũng nên nhắc lại nhận xét của yckart for( i = 0; i < arr.length; i++ )sẽ là cách tiếp cận tốt hơn vì nó bảo toàn các chỉ số chính xác so với bất kỳ thứ tự nào mà trình duyệt quyết định lưu trữ các mục (với for in). Làm như vậy cũng cho phép bạn có được chỉ số mảng của một giá trị nếu bạn cần nó.
Beejor

41

Bạn có thể sử dụng lodash _.pull (mảng biến đổi), _.pullAt (mảng biến đổi) hoặc _.without (không biến đổi mảng),

var array1 = ['a', 'b', 'c', 'd']
_.pull(array1, 'c')
console.log(array1) // ['a', 'b', 'd']

var array2 = ['e', 'f', 'g', 'h']
_.pullAt(array2, 0)
console.log(array2) // ['f', 'g', 'h']

var array3 = ['i', 'j', 'k', 'l']
var newArray = _.without(array3, 'i') // ['j', 'k', 'l']
console.log(array3) // ['i', 'j', 'k', 'l']

2
Đó không phải là JS cốt lõi như OP yêu cầu, phải không?
một số người dùng không mô tả

12
@ some-non-descript-user Bạn nói đúng. Nhưng rất nhiều người dùng như tôi đến đây để tìm kiếm một câu trả lời chung không chỉ cho OP.
Chun Yang

@ChunYang Bạn hoàn toàn đúng. Tôi đã sử dụng lodash, tại sao không sử dụng nó nếu nó tiết kiệm thời gian.
int-i

38

ES6 & không có đột biến: (Tháng 10 năm 2016)

const removeByIndex = (list, index) =>
      [
        ...list.slice(0, index),
        ...list.slice(index + 1)
      ];
         
output = removeByIndex([33,22,11,44],1) //=> [33,11,44]
      
console.log(output)


Tại sao không chỉ sử dụng filtersau đó? array.filter((_, index) => index !== removedIndex);.
user4642212

@ user4642212 bạn nói đúng! Ngoài ra, tôi thích phần gạch dưới của phong cách
Golang

36

Loại bỏ một phần tử / chuỗi cụ thể khỏi một mảng có thể được thực hiện trong một lớp lót:

theArray.splice(theArray.indexOf("stringToRemoveFromArray"), 1);

Ở đâu:

theArray : mảng bạn muốn loại bỏ một cái gì đó đặc biệt khỏi

chuỗiToRemoveFromArray : chuỗi bạn muốn loại bỏ và 1 là số lượng phần tử bạn muốn loại bỏ.

GHI CHÚ : Nếu "stringToRemoveFromArray" không nằm trong mảng của bạn, điều này sẽ loại bỏ phần tử cuối cùng của mảng.

Nó luôn luôn là thực hành tốt để kiểm tra xem phần tử có tồn tại trong mảng của bạn trước khi xóa nó không.

if (theArray.indexOf("stringToRemoveFromArray") >= 0){
   theArray.splice(theArray.indexOf("stringToRemoveFromArray"), 1);
}

Nếu bạn có quyền truy cập vào các phiên bản Ecmascript mới hơn trên máy tính của khách hàng (CẢNH BÁO, có thể không hoạt động trên các trạm cũ hơn):

var array=['1','2','3','4','5','6']
var newArray = array.filter((value)=>value!='3');

Trong đó '3' là giá trị bạn muốn xóa khỏi mảng. Mảng sau đó sẽ trở thành:['1','2','4','5','6']


Đây là câu trả lời phù hợp với tôi khi cố gắng cập nhật một mảng dựa trên nút radio.
jdavid05

4
Coi chừng, nếu "stringToRemoveFromArray"không nằm trong mảng của bạn, điều này sẽ loại bỏ phần tử cuối cùng của mảng.
Hợp nhất

35

Dưới đây là một số cách để xóa một mục khỏi mảng bằng JavaScript .

Tất cả các phương thức được mô tả không làm thay đổi mảng ban đầu , và thay vào đó tạo một mới.

Nếu bạn biết chỉ số của một mặt hàng

Giả sử bạn có một mảng và bạn muốn xóa một mục ở vị trí i.

Một phương pháp là sử dụng slice():

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const i = 3
const filteredItems = items.slice(0, i).concat(items.slice(i+1, items.length))

console.log(filteredItems)

slice()tạo ra một mảng mới với các chỉ mục mà nó nhận được. Chúng ta chỉ cần tạo một mảng mới, từ đầu đến chỉ mục mà chúng ta muốn loại bỏ và nối một mảng khác từ vị trí đầu tiên theo sau mảng mà chúng ta đã xóa đến cuối mảng.

Nếu bạn biết giá trị

Trong trường hợp này, một lựa chọn tốt là sử dụng filter(), cung cấp một cách tiếp cận khai báo hơn:

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const valueToRemove = 'c'
const filteredItems = items.filter(item => item !== valueToRemove)

console.log(filteredItems)

Điều này sử dụng các chức năng mũi tên ES6. Bạn có thể sử dụng các chức năng truyền thống để hỗ trợ các trình duyệt cũ hơn:

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const valueToRemove = 'c'
const filteredItems = items.filter(function(item) {
  return item !== valueToRemove
})

console.log(filteredItems)

hoặc bạn có thể sử dụng Babel và dịch mã ES6 trở lại ES5 để dễ đọc hơn với các trình duyệt cũ, nhưng viết JavaScript hiện đại trong mã của bạn.

Loại bỏ nhiều mục

Điều gì sẽ xảy ra nếu thay vì một mục duy nhất, bạn muốn xóa nhiều mục?

Hãy tìm giải pháp đơn giản nhất.

Theo chỉ số

Bạn chỉ có thể tạo một chức năng và loại bỏ các mục trong chuỗi:

const items = ['a', 'b', 'c', 'd', 'e', 'f']

const removeItem = (items, i) =>
  items.slice(0, i-1).concat(items.slice(i, items.length))

let filteredItems = removeItem(items, 3)
filteredItems = removeItem(filteredItems, 5)
//["a", "b", "c", "d"]

console.log(filteredItems)

Theo giá trị

Bạn có thể tìm kiếm để đưa vào bên trong chức năng gọi lại:

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const valuesToRemove = ['c', 'd']
const filteredItems = items.filter(item => !valuesToRemove.includes(item))
// ["a", "b", "e", "f"]

console.log(filteredItems)

Tránh làm biến đổi mảng ban đầu

splice()(không nên nhầm lẫn với slice()) làm thay đổi mảng ban đầu và nên tránh.

(ban đầu được đăng tại https://flaviocopes.com/how-to-remove-item-from-array/ )


34

OK, ví dụ bạn có mảng bên dưới:

var num = [1, 2, 3, 4, 5];

Và chúng tôi muốn xóa số 4. Bạn chỉ cần sử dụng mã dưới đây:

num.splice(num.indexOf(4), 1); // num will be [1, 2, 3, 5];

Nếu bạn đang sử dụng lại chức năng này, bạn viết một hàm có thể tái sử dụng sẽ được gắn vào hàm mảng gốc như bên dưới:

Array.prototype.remove = Array.prototype.remove || function(x) {
  const i = this.indexOf(x);
  if(i===-1)
      return;
  this.splice(i, 1); // num.remove(5) === [1, 2, 3];
}

Nhưng nếu bạn có mảng dưới đây thay vì một vài [5] trong mảng thì sao?

var num = [5, 6, 5, 4, 5, 1, 5];

Chúng tôi cần một vòng lặp để kiểm tra tất cả, nhưng một cách dễ dàng và hiệu quả hơn là sử dụng các hàm JavaScript tích hợp, vì vậy chúng tôi viết một hàm sử dụng bộ lọc như dưới đây:

const _removeValue = (arr, x) => arr.filter(n => n!==x);
//_removeValue([1, 2, 3, 4, 5, 5, 6, 5], 5) // Return [1, 2, 3, 4, 6]

Ngoài ra, còn có các thư viện của bên thứ ba giúp bạn thực hiện việc này, như Lodash hoặc Underscore. Để biết thêm thông tin, hãy xem lodash _.pull, _.pullAt hoặc _.without.


Có một lỗi đánh máy nhỏ. Xin hãy sửa. this.splice(num.indexOf(x), 1);=>this.splice(this.indexOf(x), 1);
TheGwa

Vui lòng không gia tăng các phần dựng sẵn (đính kèm các hàm vào Array.prototype) trong JavaScript. Điều này được coi là thực hành xấu.
aikeru

Tôi đồng ý rằng đó không phải là điều tốt nhất để làm trên thế giới, nhưng trong trường hợp này làm thế nào bạn có thể chuyển nó xuống chức năng?
Alireza

Bạn nên kiểm tra chỉ số. Nếu chỉ số = -1, mối nối (-1,1) sẽ xóa phần tử cuối cùng
Richard Chan

29

Tôi khá mới với JavaScript và cần chức năng này. Tôi chỉ viết điều này:

function removeFromArray(array, item, index) {
  while((index = array.indexOf(item)) > -1) {
    array.splice(index, 1);
  }
}

Sau đó, khi tôi muốn sử dụng nó:

//Set-up some dummy data
var dummyObj = {name:"meow"};
var dummyArray = [dummyObj, "item1", "item1", "item2"];

//Remove the dummy data
removeFromArray(dummyArray, dummyObj);
removeFromArray(dummyArray, "item2");

Đầu ra - Như mong đợi. ["item1", "item1"]

Bạn có thể có những nhu cầu khác với tôi, vì vậy bạn có thể dễ dàng sửa đổi nó cho phù hợp với họ. Tôi hi vọng điêu nay se giup được ai đo.


1
Điều này sẽ có hành vi khủng khiếp nếu mảng của bạn thực sự dài và có một vài trường hợp của phần tử trong đó. Phương thức mảng indexOf sẽ bắt đầu ngay từ đầu, vì vậy chi phí của bạn sẽ là O (n ^ 2).
Zag


27

Nếu bạn có các đối tượng phức tạp trong mảng, bạn có thể sử dụng các bộ lọc? Trong các tình huống mà $ .inArray hoặc Array.splice không dễ sử dụng. Đặc biệt là nếu các đối tượng có lẽ nông trong mảng.

Ví dụ: nếu bạn có một đối tượng với trường Id và bạn muốn xóa đối tượng khỏi một mảng:

this.array = this.array.filter(function(element, i) {
    return element.id !== idToRemove;
});

Đây là cách tôi thích làm điều đó. Sử dụng một chức năng mũi tên, nó có thể là một lót. Tôi tò mò về hiệu suất. Cũng không có giá trị gì mà điều này thay thế các mảng. Bất kỳ mã nào có tham chiếu đến mảng cũ sẽ không nhận thấy sự thay đổi.
joeytwiddle

27

Tôi muốn trả lời dựa trên ECMAScript 6 . Giả sử, bạn có một mảng như dưới đây:

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

Nếu bạn muốn xóa tại một chỉ mục đặc biệt như 2, hãy viết mã dưới đây:

arr.splice(2, 1); //=> arr became [1,2,4]

Nhưng nếu bạn muốn xóa một mục đặc biệt như 3và bạn không biết chỉ mục của nó, hãy làm như dưới đây:

arr = arr.filter(e => e !== 3); //=> arr became [1,2,4]

Gợi ý : vui lòng sử dụng chức năng mũi tên để gọi lại bộ lọc trừ khi bạn sẽ nhận được một mảng trống.


25

Cập nhật: Phương pháp này chỉ được khuyến nghị nếu bạn không thể sử dụng ECMAScript 2015 (trước đây gọi là ES6). Nếu bạn có thể sử dụng nó, các câu trả lời khác ở đây cung cấp nhiều triển khai gọn gàng hơn.


Ý chính này ở đây sẽ giải quyết vấn đề của bạn và cũng xóa tất cả các lần xuất hiện của đối số thay vì chỉ 1 (hoặc một giá trị được chỉ định).

Array.prototype.destroy = function(obj){
    // Return null if no objects were found and removed
    var destroyed = null;

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

        // Use while-loop to find adjacent equal objects
        while(this[i] === obj){

            // Remove this[i] and store it within destroyed
            destroyed = this.splice(i, 1)[0];
        }
    }

    return destroyed;
}

Sử dụng:

var x = [1, 2, 3, 3, true, false, undefined, false];

x.destroy(3);         // => 3
x.destroy(false);     // => false
x;                    // => [1, 2, true, undefined]

x.destroy(true);      // => true
x.destroy(undefined); // => undefined
x;                    // => [1, 2]

x.destroy(3);         // => null
x;                    // => [1, 2]

25

Hiệu suất

Hôm nay (2019-12-09) Tôi tiến hành kiểm tra hiệu năng trên macOS v10.13.6 (High Sierra) cho các giải pháp được chọn. tôi chỉ radelete (A), nhưng tôi không sử dụng nó so với các phương thức khác, vì nó để lại khoảng trống trong mảng.

Sự kết luận

  • giải pháp nhanh nhất là array.splice (C) (trừ Safari cho các mảng nhỏ nơi nó có lần thứ hai)
  • đối với các mảng lớn, array.slice+splice(H) là giải pháp bất biến nhanh nhất cho Firefox và Safari;Array.from(B) là nhanh nhất trong Chrome
  • giải pháp đột biến thường nhanh hơn 1,5 lần so với bất biến
  • đối với các bảng nhỏ trên Safari, đáng ngạc nhiên là giải pháp có thể thay đổi (C) chậm hơn so với giải pháp bất biến (G)

Chi tiết

Trong các thử nghiệm tôi loại bỏ phần tử giữa khỏi mảng theo nhiều cách khác nhau. Các giải pháp A, C được đưa ra. Các B, D, E, F, G, H là bất biến.

Kết quả cho mảng với 10 phần tử

Nhập mô tả hình ảnh ở đây

Trong Chrome, array.splice(C) là giải pháp tại chỗ nhanh nhất. Các array.filter(D) là giải pháp bất biến nhanh nhất. Chậm nhất làarray.slice (F). Bạn có thể thực hiện kiểm tra trên máy của bạn ở đây .

Kết quả cho mảng với 1.000.000 phần tử

Nhập mô tả hình ảnh ở đây

Trong Chrome, array.splice(C) là giải pháp tại chỗ nhanh nhất ( delete(C) tương tự nhanh - nhưng nó để lại một khoảng trống trong mảng (vì vậy nó không thực hiện 'loại bỏ hoàn toàn')). Các array.slice-splice(H) là giải pháp bất biến nhanh nhất. Chậm nhất là array.filter(D và E). Bạn có thể thực hiện kiểm tra trên máy của bạn ở đây .

So sánh cho các trình duyệt: Chrome v78.0.0, Safari v13.0.4 và Firefox v71.0.0

Nhập mô tả hình ảnh ở đây


24

Bạn không bao giờ nên thay đổi mảng của bạn. Vì điều này là trái với mô hình lập trình chức năng. Bạn có thể tạo một mảng mới mà không cần tham chiếu mảng bạn muốn thay đổi dữ liệu bằng cách sử dụng phương thức ECMAScript 6 filter;

var myArray = [1, 2, 3, 4, 5, 6];

Giả sử bạn muốn xóa 5khỏi mảng, bạn chỉ cần làm như thế này:

myArray = myArray.filter(value => value !== 5);

Điều này sẽ cung cấp cho bạn một mảng mới mà không có giá trị bạn muốn loại bỏ. Vì vậy, kết quả sẽ là:

 [1, 2, 3, 4, 6]; // 5 has been removed from this array

Để hiểu rõ hơn, bạn có thể đọc tài liệu MDN trên Array.filter .


21

Một cách tiếp cận hiện đại hơn, ECMAScript 2015 (trước đây gọi là Harmony hoặc ES 6). Được:

const items = [1, 2, 3, 4];
const index = 2;

Sau đó:

items.filter((x, i) => i !== index);

Năng suất:

[1, 2, 4]

Bạn có thể sử dụng Babeldịch vụ polyfill để đảm bảo điều này được hỗ trợ tốt trên các trình duyệt.


4
Lưu ý rằng .filtertrả về một mảng mới, không chính xác giống như loại bỏ phần tử khỏi cùng một mảng. Lợi ích của phương pháp này là bạn có thể xâu chuỗi các phương thức mảng lại với nhau. ví dụ:[1,2,3].filter(n => n%2).map(n => n*n) === [ 1, 9 ]
CodeOcelot

Tuyệt vời, nếu tôi có 600k phần tử trong mảng và muốn xóa 50k đầu tiên, bạn có thể tưởng tượng sự chậm chạp đó không? Đây không phải là giải pháp, cần có chức năng chỉ loại bỏ các phần tử và không trả về gì.
dev1223

@Seraph Vì điều đó, có lẽ bạn muốn sử dụng splicehoặc slice.
bjfletcher

@bjfletcher Thats thậm chí còn tốt hơn, trong quá trình loại bỏ, chỉ cần phân bổ 50K phần tử và ném chúng đi đâu đó. (với các phần tử 550K lát, nhưng không ném chúng từ cửa sổ).
dev1223

Tôi thích câu trả lời của bjfletker, có thể ngắn như vậy items= items.filter(x=>x!=3). Ngoài ra, OP không đưa ra bất kỳ yêu cầu nào đối với tập dữ liệu lớn.
chạy vào

21

Bạn có 1 đến 9 trong mảng và bạn muốn xóa 5. Sử dụng mã dưới đây:

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];

var newNumberArray = numberArray.filter(m => {
  return m !== 5;
});

console.log("new Array, 5 removed", newNumberArray);


Nếu bạn muốn nhiều giá trị. Ví dụ: - 1,7,8

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];

var newNumberArray = numberArray.filter(m => {
  return (m !== 1) && (m !== 7) && (m !== 8);
});

console.log("new Array, 1,7 and 8 removed", newNumberArray);


Nếu bạn muốn loại bỏ một giá trị mảng trong một mảng. Ví dụ: [3,4,5]

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var removebleArray = [3,4,5];

var newNumberArray = numberArray.filter(m => {
    return !removebleArray.includes(m);
});

console.log("new Array, [3,4,5] removed", newNumberArray);

Bao gồm trình duyệt được hỗ trợ là liên kết .


19

Tôi biết đã có rất nhiều câu trả lời, nhưng nhiều trong số chúng dường như quá phức tạp hóa vấn đề. Đây là một cách đơn giản, đệ quy để loại bỏ tất cả các phiên bản của khóa - tự gọi cho đến khi không tìm thấy chỉ mục. Có, nó chỉ hoạt động trong các trình duyệt với indexOf, nhưng nó đơn giản và có thể dễ dàng được điền.

Chức năng độc lập

function removeAll(array, key){
    var index = array.indexOf(key);

    if(index === -1) return;

    array.splice(index, 1);
    removeAll(array,key);
}

Phương pháp nguyên mẫu

Array.prototype.removeAll = function(key){
    var index = this.indexOf(key);

    if(index === -1) return;

    this.splice(index, 1);
    this.removeAll(key);
}

Chỉ cần một lưu ý, 1 cảnh báo với phương pháp này là tiềm năng cho ngăn xếp tràn. Trừ khi bạn làm việc với các mảng lớn, bạn không nên có vấn đề.
whending28

Nhưng tại sao một sự trở lại ở giữa? Nó thực sự là một tuyên bố goto.
Peter Mortensen

18

Bạn có thể thực hiện một vòng lặp ngược để đảm bảo không làm hỏng các chỉ mục, nếu có nhiều phiên bản của phần tử.

var myElement = "chocolate";
var myArray = ['chocolate', 'poptart', 'poptart', 'poptart', 'chocolate', 'poptart', 'poptart', 'chocolate'];

/* Important code */
for (var i = myArray.length - 1; i >= 0; i--) {
    if (myArray[i] == myElement) myArray.splice(i, 1);
}

Bản thử trực tiếp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.