Javascript从Array中删除Object的最快方法

时间:2015-05-18 13:37:47

标签: javascript jquery arrays performance

在速度至关重要的app上工作,数组很大 数组中包含的对象。

我使用grepfilter进行了实验,看不到明显的速度差异,变化+ - 5ms ,也尝试循环遍历数组并使用 .splice(i,1); (结果相同)。

我有一台快速机器,如果它在快速机器上总是花费相同的时间,这是否意味着在旧机器上花费的时间大致相同?

是否有更快的方法从数组中删除对象?

想要做这样的事情:

var filterTime = performance.now();
doStuff1();
var filterTimeEnd = performance.now();

var grepTime = performance.now();
doStuff2();
var grepTimeEnd = performance.now();

然后将差异存储在cookie中,以便下次加载或刷新页面时,执行最有效的方法:从数组中删除对象。

更新

过滤器实验片段

      companyMasters = companyMasters.filter(function (obj) {
      return obj.masterId != CompanyObj.masterId;
      });

3 个答案:

答案 0 :(得分:12)

您需要迭代数组以查找单个项目的任何解决方案似乎表明您正在使用的数据结构存在问题。您可能应该将它们存储在一个对象中,而不是将对象存储在数字索引的数组中,而对象中的键是您要尝试查找的masterId值。至少,如果由于其他原因需要将对象保存在数字索引数组中,可以考虑构建一个单独的对象,在该对象中将masterId值映射到主数组中的索引驻留。

所以不是这样的:

[
    {
        masterId: 'foo',
        ...
    },
    {
        masterId: 'bar',
        ...
    },
    ...
]

您将构建如下数据结构:

{
    foo: {
        masterId: 'foo',
        ...
    },
    bar: {
        masterId: 'bar',
        ...
    },
    ...
}

这将使您的代码看起来像这样:

var needle = CompanyObj.masterId;
// delete object set for 'needle' property
delete companyMaster[needle];

这为您提供了O(1)时间复杂度而不是O(n)的操作。

答案 1 :(得分:5)

现有答案已经为减少潜在问题的运行时复杂性提供了很好的解决方案。

但是我也想简短地回答原始问题,因为这是在谷歌搜索如何以最有效的方式从数组中删除时的第一页。

在不保持顺序的情况下,通过索引删除的最快方法是通过将最后一个元素分配给要删除的索引并从数组中弹出来进行删除,因为这具有O (1)运行时复杂度。

Array.prototype.mySwapDelete = function arrayMySwapDelete (index) {
    this[index] = this[this.length - 1];
    this.pop();
}

在保持订单的情况下,按顺序删除索引的最快方法是

Array.prototype.myShiftDelete = function arrayMyShiftDelete (index) {
    var stop = this.length - 1;
    while (index < stop) {
        this[index] = this[++index];
    }

    this.pop();
}

我创建了一个JS perf代码片段来对不同的功能进行基准测试:https://jsperf.com/array-remove-by-index

当想要过滤时,与调用原生的.filter()函数(分配一个新数组)相比,在适当位置进行过滤和移位要快得多。此就位过滤器还维护顺序:

Array.prototype.myShiftFilter = function arrayMyShiftFilter (predicate) {
    let i, j;

    for (i = 0, j = 0; i < this.length; ++i) {
        if (predicate(this[i])) {
            this[j] = this[i];
            ++j;
        }
    }

    while (j < this.length) {
        this.pop();
    }
}

另请参阅JS Perf代码段以获取基准:https://jsperf.com/array-filter-in-place

答案 2 :(得分:3)

不是一遍又一遍地遍历数组以删除一个项目,而是构建一个可用于一次过滤掉所有项目的地图:

var map = {};
for (var i = 0; i < itemsToRemove.length; i++) {
  map[itemsToRemove[i]] = 1;
}

companyMasters = companyMasters.filter(function (obj) {
  return !(obj.masterId in map);
});