JavaScript数组中从中删除元素的简洁方法(使用jQuery、coffeescript)

59

有很多关于这个问题的提问,尤其是:jQuery版的数组包含使用splice方法的解决方案等等。然而,它们都似乎很复杂和烦人。

结合javascript、jQuery和coffeescript的强大功能,最干净的从javascript数组中删除元素的方法是什么?我们不知道预先的索引。代码如下:

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

如果没有好的内置方法,如何干净地扩展JavaScript数组以支持这种方法?如果有帮助的话,我实际上是将数组用作集合。最好的解决方案应该能够在带有jQuery支持的coffeescript中良好地工作。此外,我不关心速度,而是优先考虑清晰、简单的代码。

8个回答

88

CoffeeScript:

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

这个方法会简单地将在位置t的元素删掉,该位置是e被找到的索引(如果它确实被找到了t > -1)。 Coffeescript 将其转换为:

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

如果您想删除所有匹配的元素并返回一个新的数组,可以使用CoffeeScript和jQuery:
Array::remove = (v) -> $.grep @,(e)->e!=v

翻译成中文:

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

不使用jQuery的grep函数实现相同的功能:

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

翻译为:

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
显然,你在使用CoffeeScript的时间比我长得多; 对于看起来非常惯用的东西,我给个赞。 - Domenic
1
感谢@Amir提供了一份出色的、地道的答案。其他的回答也很有帮助,但我喜欢这个答案,因为它利用了现有的工具使事情更简单。只有一个小改动:我可能会将其称为Array::removing,例如smaller_array = larger_array.removing(something),这样就清楚地表明它返回一个新的数组。 - Peter
2
该死的CoffeeScript真美。我相信你可以摆脱@.indexOf,只需使用@indexOf(没有点)。 - George R
1
摆脱不必要的concat:Array::remove = (v) -> @splice i, 1 if i = @indexOf(v) > -1 - Ricardo Tomasi
4
由于这个 $.grep @,(e)->e!=v,我再也不会考虑使用 CoffeeScript 了。可读性等于零。 - PiTheNumber
显示剩余3条评论

28

使用原生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);

仅需使用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);

虽然我当然应该进行基准测试,但我认为这可能会更慢,因为indexOf是O(n),给出总复杂度O(n * m + n),其中m是匹配数。我的答案只需一次遍历,给出O(n)的复杂度。 - Domenic
@Domenic:当然。.index() 不是很快,但足够公平且代码更少。如果我追求性能,我会使用 while() 循环:请参见 http://jsperf.com/benchmark-for-domenic - jAndy
哈哈,你的 jsPerf 揭示了 Chrome 和 Firefox 4b10 之间的差异,不错!在我的 Firefox 中,“for”版本比你的 Chrome 版本运行得更快。酷! - Domenic
@Domenic:确实很奇怪。 - jAndy

14

使用jQuery非常容易实现:

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

说明:

splice返回被移除的元素,不要使用myArray = myArray.splice()myArray.splice(index,1) 表示“从数组中删除索引为'index'的元素。”

$.inArray 返回值在数组中的索引,如果值不在数组中则返回-1。


1
几乎和使用原生JS一样容易。 - Jaroslav Záruba
1
这似乎只删除了一个匹配的条目。数组可以包含多个相同值的条目。 - Ben Simpson
2
问题是:“从Javascript数组中删除一个元素的最干净的方法是什么?” - adavea

9

这看起来非常清晰易懂;与其他答案不同,它考虑了元素可能出现多次的情况。

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

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

4

如果您也使用CoffeeScript创建者的underscore.js库,以下一行代码将很好地起作用:

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

或者在js中:

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

4

虽然您要求使用Coffeescript或jQuery进行清洁的方法,但我认为最清晰的方法是使用原生JavaScript方法filter

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

虽然使用coffeescript更简洁,但它所翻译出来的javascript代码与原始代码完全相同,因此我认为这只是视觉上的区别,而不是coffeescript的高级功能:

array.filter (item) -> item isnt match

在传统浏览器中不支持Filter,但 Mozilla 提供了一个符合 ECMA 标准的polyfill。我认为这是一个非常安全的方法,因为你只需要将旧浏览器升级到现代标准,并且你没有在 polyfill 中发明任何新功能。

如果您特别寻找 jQuery 或 Coffeescript 的方法,那么很抱歉,但我认为您主要是想要一个库方法,因为您不知道有一个干净的 JavaScript 方法。

这就是它,不需要使用任何库!


1
我喜欢这种方法和推理。 - Peter

3

这只是对Amir的精彩解决方案做了轻微修改:

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

如果列表中有该元素,则返回该元素,因此您可以执行以下操作:

do_something 100 if a.remove(100)

删除咖啡脚本翻译为以下JavaScript代码:

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

1

您可以尝试使用jQuery的grep实用程序:

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

这里可能存在性能问题,因为你在技术上导致变量引用了一个新的数组;你并没有真正修改原始数组。假设原始数组没有被其他地方引用,垃圾回收器应该很快就会处理掉它。这对我来说从未是个问题,但其他人可能知道得更好。干杯!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接