Câu hỏi Làm thế nào để loại bỏ một phần tử cụ thể khỏi một mảng trong JavaScript?


Tôi có một loạt các số nguyên và tôi đang sử dụng .push() phương pháp để thêm các yếu tố vào nó.

Có một cách đơn giản để loại bỏ một yếu tố cụ thể từ một mảng? Tương đương với một cái gì đó như array.remove(int);.

tôi phải dùng cốt lõi JavaScript - Không khuôn khổ được cho phép.


6131
2018-04-23 22:17


gốc


Nếu bạn cần hỗ trợ <IE9 (thở dài) sau đó kiểm tra câu hỏi SO này về indexOf trong IE. - Scotty.NET
(lodash) mảng = ['a', 'b', 'c']; _.pull (mảng, 'a') // mảng => ['b', 'c']; Xem thêm stackoverflow.com/questions/5767325/… - Chun Yang
phương pháp lọc có thể làm những gì bạn muốn. - Salvador Dali
Bạn có thể sử dụng xóa nhưng nó sẽ không tái sắp xếp chỉ mục thay vì nó sẽ đặt khe này thành 'undefined × 1'. Ví dụ: var list = [1,2,3,4,5,6] -> delete list [1] -> [1, undefined × 1, 3, 4, 5, 6]. - DevWL
Đây là điểm chuẩn hiệu suất của hai khả năng chính: jsben.ch/#/b4Ume - EscapeNetscape


Các câu trả lời:


Tìm index của phần tử mảng mà bạn muốn xóa, 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.

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

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


chú thích: hỗ trợ trình duyệt cho indexOf có giới hạn


8923
2018-04-23 22:23



@ Peter, có bạn có thể đúng. Bài viết này giải thích thêm và có giải pháp cho các trình duyệt không tương thích: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… - Tom Wadley
Nguy hiểm! Nếu bạn đang làm việc với các giá trị động (thêm và loại bỏ các giá trị động từ mảng) và giá trị không tồn tại trong mảng (chỉ số trở thành -1), mã ở trên sẽ loại bỏ phần tử cuối cùng của mảng. - Adrian P.
@AlexandreWiechersVaz Tất nhiên nó bảo tồn trật tự, nếu không thì nó sẽ hoàn toàn vô giá trị - TheZ
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ã đưa ra ở đây
@AdrianP. array.indexOf(testValue) trên mảng trống sẽ là -1, và nếu bạn đang thử nghiệm cho rằng sau đó không có mối nối. Có lẽ câu trả lời đã thay đổi kể từ đó. - UpTheCreek


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

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

array.splice(i, 1);

Nếu bạn muốn xóa mọi phần tử có giá trị number từ 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ử ở chỉ mục i khô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];

896
2018-04-23 22:20



delete khô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
@ FelixKling Nó phụ thuộc, nó hoạt động nếu bạn muốn làm cho nó để array.hasOwnProperty(i) trả về false và có phần tử ở vị trí đó undefined. Nhưng tôi sẽ thừa nhận rằng đó không phải là một điều rất phổ biến để làm. - Peter Olson
delete sẽ không cập nhật độ dài của mảng không thực sự xóa phần tử, chỉ thay thế nó bằng giá trị đặc biệt undefined. - diosney
@ diosney Tôi không biết ý bạn là gì khi bạn nói nó không thực sự xóa bỏ yếu 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ó xóa cả chỉ mục và giá trị khỏi mảng, tức là sau delete array[0], "0" in array sẽ trả về false. - Peter Olson
xóa là một cơ chế tốt nếu bạn đang xử lý các thuộc tính được đặt tên var array=[];array['red']=1;array['green']=2;array['blue']=3;delete array['green']; - Jefferey Cave


Đã 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 (https://en.wikipedia.org/wiki/Occam%27s_razor)
  • 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 JS chuẩn, nếu trình duyệt của bạn không hỗ trợ chúng - sử dụng polyfill

Trong ví dụ mã này tôi sử dụng "array.filter (...)" chức năng để loại bỏ các mục không mong muốn từ mảng, chức năng này không thay đổi mảng ban đầu và tạo ra 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ụ: IE 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 Edition 5 còn gọi là JS 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 ]

Đang xóa mục (mã ES2015)

let value = 3

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

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

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

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


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

Một lợi thế bổ sung của phương pháp này là bạn có thể xóa 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 ]

QUAN TRỌNG Chức năng "array.includes (...)" không được hỗ trợ trong IE, 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 14 phiên bản đây là polyfill từ Mozilla

Xóa nhiều mục (ES2018 thử nghiệm tiên tiến)?)

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


678
2017-12-19 19:54



nhưng, đôi khi chúng ta muốn loại bỏ phần tử khỏi mảng ban đầu (không thay đổi), ví dụ mảng được sử dụng trong Angular 2 * ngFor chỉ thị - Ravinder Payal
Tốt hơn so với giải pháp được chấp nhận bởi vì nó không giả định chỉ có một sự xuất hiện của một trận đấu và bất biến là thích hợp hơn - Greg
Sử dụng bộ lọc đẹp hơn rất nhiều so với sử dụng mối nối. Quá đơn giản. - user3344977
filter phải chậm hơn nhiều đối với một mảng lớn? - Nathan
Phương pháp siêu chậm. - highmaintenance


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

Nếu bạn muốn một khe trống, xóa là tốt:

delete array[ index ];

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

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 làm điều đó theo thứ tự nào đó, bạn có thể sử dụng array.pop() cho ngườ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 mục đó).

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


359
2018-04-23 22:32



Cần lưu ý rằng var value sẽ không lưu trữ giá trị đã xóa nhưng một mảng chứa giá trị đã xóa. - Jakub
delete khô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
Nếu bạn muốn "trống một khe", hãy sử dụng array[index] = undefined;. Sử dụng delete sẽ phá hủy tối ưu hóa. - Bergi
@ Jakub bình luận 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 tôi bằng cách nào đó bị hỏng ... - Pascal


Một người bạn đang gặp vấn đề trong Internet Explorer 8và cho tôi xem anh ấy đã làm gì. Tôi nói với anh ấy điều đó là sai, và anh ta nói với tôi rằng anh ta 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ụ như Internet Explorer 8) và nó sẽ chỉ xóa lần xuất hiện đầu tiên của mục.

Loại bỏ TẤT CẢ các cá thể 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ì chỉ mục và độ dài sẽ thay đổi khi mục được xóa) và xóa mục nếu nó được tìm thấy. Nó hoạt động trong tất cả các trình duyệt.


228
2017-08-10 19:21



@ không phải vì vòng lặp bắt đầu lúc i = arr.length -1 hoặc là i-- làm cho nó giống như chỉ mục tối đa. arr.length chỉ là giá trị ban đầu cho i. i-- sẽ luôn là trung thực (và giảm 1 tại mỗi vòng lặp op) cho đến khi nó bằng 0 (một giá trị giả) và vòng lặp sẽ dừng lại. - gabeno
Hàm thứ hai là khá kém hiệu quả. Trên mỗi lần lặp lại "indexOf" sẽ bắt đầu tìm kiếm từ đầu mảng. - Ujeenator
@AmberdeBlack, trên bộ sưu tập có hơn 1 lần xuất hiện mục, tốt hơn hết là gọi bộ lọc phương pháp thay thế arr.filter(function (el) { return el !== item }), tránh cần 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 công việc cần phải được thực hiện. - Eugene Kuzmenko
@AlJey, nó chỉ có sẵn từ IE9 +. Vẫn còn một cơ hội mà nó sẽ không hoạt động. - Ujeenator
Câu trả lời này có hiệu quả đối với tôi vì tôi cần một số mục bị xóa nhưng không cần theo thứ tự cụ thể nào. Sự tiến triển ngược của vòng lặp for ở đây xử lý việc loại bỏ các mục khỏi mảng một cách hoàn hảo. - mintedsky


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

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

  2. xóa bỏ: 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 cho việc xóa các thuộc tính của đối tượng nhưng không tốt cho mảng. Nó là tốt hơn để sử dụng splice cho mảng.

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

Bạn cũng có thể mong đợi có lỗ trong số chỉ mục sau khi sử dụng xóa, ví dụ: bạn có thể kết thúc với chỉ số 1,3,4,8,9,11 và chiều dài như trước khi sử dụng xóa. Trong trường hợp đó, tất cả được lập chỉ mục for vòng lặp 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 delete vì một lý do nào đó, bạn nên sử dụng for each vòng lặp khi bạn cần lặp qua mảng. Như một vấn đề của thực tế, luôn luôn tránh sử dụng lập chỉ mục cho các vòng, nếu có thể. Bằng cách đó, mã sẽ mạnh mẽ hơn và ít bị các vấn đề với các chỉ mục.


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



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 công tác khác nhau, chúng có thể kết thúc xung đột với nhau. - Charlie Kilian
Điều này làm việc là tốt, tôi đã chọn để đi với chức năng indexOf cuối cùng mặc dù. Cảm ơn đã giúp đỡ! - Walker
Ý tưởng tồi, hãy xem bài đăng này: stackoverflow.com/questions/948358/array-prototype-problem - MMeah
Nếu bạn đang làm for in trên một mảng, bạn đã có một vấn đề. - Zirak
nếu bạn làm for in trên mảng, bạn đã có vấn đề lớn hơn. - Rainb