【问题标题】:JavaScript - Efficient way to compare very large array of objectsJavaScript - 比较非常大的对象数组的有效方法
【发布时间】:2019-12-16 08:22:34
【问题描述】:

我有 2 组非常大的数据,由于我的环境的限制,我需要在客户端进行比较。

对应的对象数组的大小每个都超过 450k,我一直在测试不同的方法来比较它们(For 循环、.find、.indexOf、.reduce、$.grep)并且它们都运行得很慢(每分钟大约 700 次计算)。

检查包括找出一个数组中的每个对象是否已经包含在另一个数组中,例如:

var Arr1 = [{ID:2, Name: Bar}, {ID:1, Name: Foo}]
var Arr2 = [{ID:2, Name: Fu}, {ID:2, Name: Bar}] 

如果 Arr2 中的任何对象被任何属性包含在第一个对象中,在这种情况下 (Arr2[1].Name == Arr1[0].Name)?将返回true

在这种情况下,我会将其推送到我们可以命名的新对象数组 Found:Found.push(Arr1[0])

我当然需要对数组中的所有 400k+ 对象执行此检查,所以它会变得非常慢。

我知道我的请求中有几个“但是”,例如可用 RAM 和处理器速度,但假设环境完美,最快的方法是什么?

【问题讨论】:

  • 你能举一个输入和预期输出的例子吗?
  • 只是好奇,您需要将这些数组保持为 400k+ 还是可以将它们分解为一些更小的逻辑分组?我也很好奇你的环境有什么限制......服务器端的一些预处理可能真的有帮助。
  • 我认为你的任务是后端方面
  • 是的,请给我一分钟,我可以得到一些样本数据。至于其他问题,我正在处理直接来自我客户数据库的提取物,他们拒绝在他们这边执行任何更改以减少我的负载,我无法在中间设置另一个数据库来帮助解决这个问题,因为经济限制。是的,我们可以根据需要将数组分成任意多的块,我尝试将它们分开,但结果与整个过程几乎相同。
  • 只是一个附带的问题:数据是来自服务器还是在客户端生成?如果是这样,元素是否已经订购?这是您唯一可以获得的格式吗?

标签: javascript arrays performance object compare


【解决方案1】:

我认为最重要的是确保您的复杂性不会达到O(n * m)n 是 Arr1 的长度,m 是 Arr2 的长度)。

循环第二个数组并在第一个数组上使用indexOffind,将给您提供m * n 操作的最坏情况(如果Arr2 中的任何项目都没有出现在Arr1 中)。

因此,您应该首先创建 Arr2 的索引,以确保您在遍历 Arr1 时的查找成本低廉。

困难的部分是确定如何索引您的数组以支持快速访问。一种方法是创建一个hash 函数:

// Include the properties that determine equality in this hash function
const hash = ({ Name, Results }) => `${Name}|${Results}`;

console.log(
  hash({ Name: "john.doe", Results: "Check", Timestamp: "-", Period: "Q2" })
);

使用此方法,您可以通过遍历Arr2 中的所有项目来创建{ string: Object } 的索引一次

const hash = ({ Name, Results }) => `${Name}|${Results}`;
const arr2 = [
  { Name: "john", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "jane", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "aisha", Results: "Check", Timestamp: "-", Period: "Q2" }
];

console.log(
  Object.fromEntries(arr2.map(x => [hash(x), x])) 
);

注意:根据 javascript 引擎,最好使用 forwhile 循环重写它。首先创建入口数组也会消耗一些内存。在这里,我只是想解释一下一般的方法。


使用此索引,找到与 Arr2 元素的匹配项将(几乎?)具有恒定的时间复杂度。

const hash = ({ Name, Results }) => `${Name}|${Results}`;
const arr2 = [
  { Name: "john", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "jane", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "aisha", Results: "Check", Timestamp: "-", Period: "Q2" }
];

const arr1 = [
  { Name: "john", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "jane", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "aisha", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "robert", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "ellen", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "tin", Results: "Check", Timestamp: "-", Period: "Q2" }
];


const index = Object.fromEntries(arr2.map(x => [hash(x), x]));

const results = arr1.filter(p => index.hasOwnProperty(hash(p)));

console.log(`In both arrays: ${results.map(p => p.Name).join(", ")}`);

我不是计算机科学专业的毕业生,但我认为这将使您接近 O(n + m) 复杂性,这对于 2 x 450k 项应该是可行的?


附:如果Object.fromEntriesmapfilter 速度变慢,您可以重写为:

const arr2 = [
  { Name: "john", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "jane", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "aisha", Results: "Check", Timestamp: "-", Period: "Q2" }
];

const arr1 = [
  { Name: "john", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "jane", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "aisha", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "robert", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "ellen", Results: "Check", Timestamp: "-", Period: "Q2" },
  { Name: "tin", Results: "Check", Timestamp: "-", Period: "Q2" }
];


const index = {};
for (let i = 0; i < arr2.length; i += 1) {
  const item = arr2[i];
  index[`${item.Name}|${item.Results}`] = item;
}

const results = [];
for (let i = 0; i < arr1.length; i += 1) {
  const item = arr1[i];
  const match = index[`${item.Name}|${item.Results}`];
  if (match) {
    results.push(match);
  }
}

console.log(`In both arrays: ${results.map(p => p.Name).join(", ")}`);

【讨论】:

  • 这听起来很有希望!我会试一试,如果有效,我会将其标记为已回答!非常感谢。
猜你喜欢
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
  • 2014-05-15
相关资源
最近更新 更多