2011-01-28 29 views
59

Có nhiều câu hỏi về điều này, không kém: jQuery version of array contains, a solution with the splice method và nhiều hơn nữa. Tuy nhiên, tất cả chúng đều có vẻ phức tạp và khó chịu.Cách dọn dẹp yếu tố khỏi mảng javascript (với jQuery, coffeescript)

Với sức mạnh kết hợp của javascript, jQuery và coffeescript, cách sạch nhất để xóa phần tử khỏi mảng javascript là gì? Chúng tôi không biết trước chỉ số. Trong mã:

a = [4,8,2,3] 
a.remove(8)  # a is now [4,2,3] 

Không có phương pháp tích hợp tốt, cách mở rộng mảng javascript để hỗ trợ phương pháp như vậy là gì? Nếu nó giúp, tôi thực sự sử dụng mảng như bộ. Giải pháp lý tưởng sẽ hoạt động tốt trong coffeescript với sự hỗ trợ của jQuery. Ngoài ra, tôi không thể quan tâm đến tốc độ, nhưng thay vào đó ưu tiên mã rõ ràng, đơn giản.

Trả lời

87

CoffeeScript:

Array::remove = (e) -> @[t..t] = [] if (t = @indexOf(e)) > -1 

Mà chỉ đơn giản là chỗ nối ra các phần tử ở vị trí t, chỉ số nơi e đã được tìm thấy (nếu nó đã thực sự tìm thấy t > -1) .Coffeescript dịch này để:

Array.prototype.remove = function(e) { 
    var t, _ref; 
    if ((t = this.indexOf(e)) > -1) { 
     return ([].splice.apply(this, [t, t - t + 1].concat(_ref = [])), _ref); 
    } 
}; 

Và nếu bạn muốn loại bỏ tất cả các yếu tố phù hợp, và trả về một mảng mới, sử dụng CoffeeScript và jQuery:

Array::remove = (v) -> $.grep @,(e)->e!=v 

mà dịch thành:

Array.prototype.remove = function(v) { 
    return $.grep(this, function(e) { 
     return e !== v; 
    }); 
}; 

Hoặc làm tương tự mà không có grep của jQuery:

Array::filterOutValue = (v) -> x for x in @ when x!=v 

mà dịch để:

Array.prototype.filterOutValue = function(v) { 
    var x, _i, _len, _results; 
    _results = []; 
    for (_i = 0, _len = this.length; _i < _len; _i++) { 
     x = this[_i]; 
     if (x !== v) { 
      _results.push(x); 
     } 
    } 
    return _results; 
}; 
+5

Rõ ràng bạn đã sử dụng CoffeeScript lâu hơn tôi nhiều; 1 cho những gì trông rất thành ngữ. – Domenic

+1

Cảm ơn @Amir vì một câu trả lời tuyệt vời, thành ngữ. Các câu trả lời khác cũng hữu ích; Tôi thích cái này vì nó sử dụng các công cụ có sẵn để làm cho mọi việc đơn giản hơn. Một thay đổi nhỏ: có lẽ tôi sẽ gọi nó là 'Array :: remove', như trong' small_array = larger_array.removing (something) ', vì vậy rõ ràng là nó trả về một mảng mới. – Peter

+0

Ý bạn là đối với câu hỏi thứ hai? Cá nhân tôi sẽ gọi nó là 'filterOutValue', nhưng với từng cái riêng của mình. Các biến và chức năng đặt tên là phần khó nhất trong việc lập trình :) – Amir

27

Sử dụng vani Javascript:

Array.prototype.remove = function(elem) { 
    var match = -1; 

    while((match = this.indexOf(elem)) > -1) { 
     this.splice(match, 1); 
    } 
}; 

var a = [4, 8, 2, 3]; 

a.remove(8); 

Chỉ jQuery:

jQuery.removeFromArray = function(value, arr) { 
    return jQuery.grep(arr, function(elem, index) { 
     return elem !== value; 
    }); 
}; 

var a = [4, 8, 2, 3]; 

a = jQuery.removeFromArray(8, a); 
+0

Mặc dù tôi tất nhiên nên điểm chuẩn, tôi nghi ngờ điều này sẽ chậm hơn do 'indexOf' là O (n), cho bạn tổng độ phức tạp O (n * m + n) cho m số kết quả phù hợp. Câu trả lời của tôi tạo ra một đường chuyền, cho độ phức tạp O (n). – Domenic

+0

@Domenic: tất nhiên. '.index()' không phải là nhanh, nhưng nó đủ công bằng và ít mã. Nếu sau buổi biểu diễn, tôi sẽ sử dụng vòng lặp while (while): xem http://jsperf.com/benchmark-for-domenic – jAndy

+0

Haha, jsPerf của bạn đã phát hiện ra sự khác biệt giữa Chrome và Firefox 4b10, tốt đẹp! Phiên bản 'for' chạy nhanh hơn trong Firefox của tôi so với phiên bản Chrome của bạn. Mát mẻ! – Domenic

9

này có vẻ khá sạch sẽ và dễ hiểu; không giống như các câu trả lời khác, nó đưa vào tài khoản khả năng của một phần tử hiển thị nhiều hơn một lần.

Array.prototype.remove = function (value) { 
    for (var i = 0; i < this.length;) { 
     if (this[i] === value) { 
      this.splice(i, 1); 
     } else { 
      ++i; 
     } 
    } 
} 

Trong CoffeeScript:

Array::remove = (value) -> 
    i = 0 
    while i < @length 
     if @[i] == value 
      @splice i, 1 
     else 
      ++i 
    return @ 
3

Đây chỉ là một thay đổi nhỏ để Amir's awesome solution:

Array::remove = (e) -> @splice(t,1)[0] if (t = @indexOf(e)) > -1 

trả về phần tử khi và chỉ khi danh sách có nó, vì vậy bạn có thể làm một cái gì đó như:

do_something 100 if a.remove(100) 

Loại bỏ tập lệnh cà phê được dịch sang javascript này:

Array.prototype.remove = function(e) { 
    var t, _ref; 
    if ((t = this.indexOf(e)) > -1) { 
    return ([].splice.apply(this, [t, t - t + 1].concat(_ref = [])), _ref); 
    }}; 
4

nếu bạn cũng đang sử dụng thư viện underscore.js CoffeeScript tác giả của, đây là một lớp lót sẽ làm việc độc đáo:

a = _(a).reject (v)-> v is e 

hoặc trong js:

a = _(a).reject(function(v) { return v == e; }); 
14

Đây là thực sự dễ dàng với jQuery:

var index = $.inArray("value", myArray); 
if(index != -1) 
{ 
    myArray.splice(index, 1); 
} 

Ghi chú:

splice trả về các phần tử đã bị xóa, vì vậy đừng làm myArray = myArray.splice(). myArray.splice(index,1) có nghĩa là "loại bỏ phần tử mảng tại chỉ mục 'index' khỏi mảng".

$.inArray trả về chỉ mục trong mảng giá trị bạn đang tìm kiếm hoặc -1 nếu giá trị không nằm trong mảng.

+1

gần như dễ dàng như với vanilla JS –

+1

Điều này dường như chỉ xóa một mục nhập trùng khớp. Một mảng có thể chứa nhiều mục nhập của cùng một giá trị. –

+2

Câu hỏi đặt ra: "cách sạch nhất để xóa ** phần tử ** từ mảng javascript là gì?" – adavea

1

Bạn chỉ có thể thử tiện ích grep jQuery:

a = [4,8,2,3] 
$.grep(a,function(v){return v!=8;}) 

Có thể có một vấn đề hiệu suất ở đây, như bạn đang về mặt kỹ thuật gây ra biến để tham khảo một mới mảng; bạn không thực sự sửa đổi bản gốc. Giả sử bản gốc không được tham chiếu ở đâu đó khác, bộ thu gom rác nên thực hiện hoặc điều này khá nhanh. Điều này chưa bao giờ là vấn đề đối với tôi, nhưng những người khác có thể biết rõ hơn. Chúc mừng!

4

Mặc dù bạn đang yêu cầu một cách tiếp cận sạch sử dụng Coffeescript hoặc jQuery, tôi tìm cách tiếp cận sạch đang sử dụng vani javascript phương pháp filter:

array.filter(function (item) { return item !== match }); 

Có vẻ sạch hơn trong coffeescript nhưng điều này dịch với cùng javascript chính xác , vì vậy tôi chỉ coi đó là một sự khác biệt hình ảnh, và không phải là một tính năng tiên tiến của coffeescript:

array.filter (item) -> item isnt match 

Lọc không được hỗ trợ trong các trình duyệt di sản, nhưng Mozilla cung cấp một polyfill rằng adhe chuyển sang tiêu chuẩn ECMA. Tôi nghĩ đây là một cách tiếp cận hoàn toàn an toàn bởi vì bạn chỉ đưa các trình duyệt cũ vào các tiêu chuẩn hiện đại, và bạn không phát minh ra bất kỳ chức năng mới nào trong polyfill của bạn.

Xin lỗi nếu bạn đang tìm kiếm một phương pháp chỉ jQuery hoặc Coffeescript, nhưng tôi nghĩ bạn chủ yếu yêu cầu một phương thức thư viện vì bạn không biết về phương thức javascript thuần túy.

Ở đó bạn có, không cần thư viện!

+1

Tôi thích cách tiếp cận và lý luận này. – Peter

Các vấn đề liên quan