Javascript 降低嵌套for循环的时间复杂性

Javascript 降低嵌套for循环的时间复杂性,javascript,Javascript,基本上,我试图降低我拥有的一系列函数的时间复杂度 const companies = [ { staff: [ { id: 1, qualities: [ { id: 2, tags: [ 'efficient', 'hard-working' ] }

基本上,我试图降低我拥有的一系列函数的时间复杂度

const companies = [
    {
     staff: [
      {
        id: 1,
        qualities: [
          {
            id: 2,
            tags: [
              'efficient',
              'hard-working'
            ]
          }
        ]
      }
    ]
  }
]
因此,我有一个
数组
公司
,其中有另一个
数组
员工
,然后又有一个
数组
质量
,最后还有一个
数组
标签

现在我有了一个预先确定的标签列表,我需要为每个公司匹配用户

companies: [
 xyz: [
   {
    tag: 'smart',
    users: []
   }
 ],
 // ...
];
所以基本上我需要遍历每个预先确定的标签,然后遍历每个公司,然后遍历每个用户,遍历每个标签来创建这个视图

基本上是这样的

const tags = [
  'smart',
  'hard-working',
  'efficient'
];

getUserTags(tagName) {
  const users = [];
  companies.forEach(company => {
    company.users.forEach(user => {
      user.tags.forEach(tag => {
        if (tag === tagName) {
          users.push(user);
        }
      });
    });  
  });
  return users; 
}
正如你所看到的,这是超低效的,大O的结果是O(n^4),这很可怕

我怎样才能解决这个问题

可能有50个标记[…],因此对于每个标记,它必须[调用
getUserTags
函数]循环遍历每个用户,然后循环遍历每个用户标记,以查看是否匹配以获得总计数

不,你不应该这样做。相反,只循环一次用户和每个用户的标记,并按标记名映射数据结构在数组中收集它们。使用类似

getUsersByTags(companies, tags) {
  let map = new Map();
  for (const tag of tags) {
    map.set(tag, []);
  }
  for (const company of companies) {
    for (const user of company.staff) {
      for (const quality of user.qualities) {
        for (const tag of quality.tags) {
          const n = tag.name;
          if (map.has(n))
            map.get(n).push(user);
        }
      }
    }
  }
  return map;
}

您无法避免遍历整个公司员工质量标签结构来访问所有标签数据。就时间复杂性而言,你说你需要4层抽象。(在对你的问题进行编辑之前,是3个问题:用户、质量、标签)。现在我们有了公司、员工、品质和标签。使用此结构,您应该期望O(n^4)。下面的代码不尝试更改复杂性级别,但可能会更快,因为它只保留计数而不是项目,并使用include来缩短循环的出口

这可以使用和来完成


我们使用
reduce
通过将标识为包含在每个质量项目中的标记值相加,从数组的累加中获取单个值。

如果您只想对它们进行计数,不要将它们放入数组中,而只是增加一个整数。您是真的想让代码更快,还是更易于读取/维护?它们往往不是一回事。如果是前者,那么在最坏的情况下它现在有多慢?不,如果你的数据就是这样的结构,那么就无法避免完全遍历它。除了选择一个更合适的数据结构作为输入,你无法降低时间复杂度。@Bergi不幸的是,我确实需要将它们存储在数组中-因为我做了进一步的修改Minor:原始的
公司
对象似乎有不正确的结构。哇,发布后几秒钟立即进行向下投票。甚至没有足够的时间阅读我的答案。下层选民愿意给出一个原因吗?谢谢,是的,实际上地图是不需要的。我们也可以使用
includes
,因为一个标签在质量标签列表中出现多次是没有意义的。不清楚为什么这个解决方案会降低时间复杂度?@SmokeyDawson谢谢,将
用户
重命名为
公司
并不会真正改变我的答案。第二个代码段中的结构(
公司:[…
)语法无效,我不知道该怎么办?同样在编辑中,您删除了正在计算标记的事实,并将其替换为仅通用的
//do stuff
。在不知道结果是什么的情况下,我们无法建议任何更好的算法。好的,已更新,但答案的要点不变。无返回值。
let getCountOfTags = (users, tagName) => users.reduce(
    (acc, item) => acc + item.qualities.reduce(
        (qAcc, q) => qAcc + (q.tags.includes(tagName) ? 1 : 0),
        0
    ), 
    0
);