【问题标题】:Filtering a large javascript object recursively递归过滤大型javascript对象
【发布时间】:2020-09-26 13:32:02
【问题描述】:

我在反应中递归地过滤一个大型 javascript 对象(37000 行的 JSON 文件)。在我过滤了对象后,我将它作为道具发送给渲染对象的组件。

这是我目前的功能,它适用于所有较小的文件,但对于较大的文件来说它相当慢。我可以对该功能进行任何改进以使其执行得更快吗?

export const filterBySubstringKey = (data: any, value: string) => {
  const iterate = (object: any, result: any) => {
    return Object.keys(object).reduce((acc, key) => {
      let tempResult = {};
      if (key.toLowerCase().indexOf(value.toLowerCase()) !== -1) {
        result[key] = object[key];
        return true;
      }
      if (object[key] !== null && typeof object[key] === 'object' && iterate(object[key], tempResult)) {
        result[key] = tempResult;
        return true;
      }
      return acc;
    }, false);
  };

  let result = {};
  iterate(data, result);
  return result;
};

【问题讨论】:

  • 第一个优化我可以看到value.toLowerCase(),只需执行一次并存储在一个变量中。
  • Next -> Object.keys,因为您可能也在追求价值,您可能会更改为 Object.entries 而不是 object[key]
  • 感谢您的建议。更改 lowerCase 值是一种快速的方法。但是,当我按值搜索时,会调用一个单独的类似函数。
  • 您可以尝试重写代码以使用循环而不是递归,因为循环通常更快 (stackoverflow.com/questions/9386375/…)

标签: javascript json reactjs


【解决方案1】:

您可以做的不多,但我建议您采取以下措施,这可能会稍微改善时间安排:

  • 不要将第二个参数传递给iterate,而是让return 值是您要从中获取的对象。

  • 使用老式的for 循环而不是数组方法。

  • 就像您在 cmets 中所说的那样:只调用一次 value.toLowerCase()

  • 仅从object[key] 读取一次

  • 使用includes 代替indexOf

export const filterBySubstringKey = (data: any, value: string) => {
  value = value.toLowerCase();

  const iterate = (object: any) => {
    let result = {};
    for (let key in object) { // Assuming no enumerable inherited props
      let val = object[key];
      if (key.toLowerCase().includes(value)) {
        result[key] = val;
      } else if (val !== null && typeof val === 'object') {
        let temp = iterate(val);
        if (temp) result[key] = temp;
      }
    }
    for (let key in result) return result; // When result is not empty
    // default: return undefined
  };

  return iterate(data);
};

【讨论】:

    【解决方案2】:

    我创建了 3 个变体。我稍微简化了你的代码。 这是性能结果jsperf。结果因运行而异,但变体 4 是最快的

    编辑: 在 v5 中添加了更多优化,它的性能优于其他所有。

    const filterBySubstringKey5 = (data, value) => {
      const valueLow = value.toLowerCase()
      const iterate = object => {
        let res = {};
        for (const key in object) {
          const ok = object[key]
          if (typeof ok === "object") {
            res[key] = iterate(ok);
          } else {
            if (key.toLowerCase().indexOf(valueLow) !== -1) {
              res[key] = ok;
            }
          }
        }
        return res;
      };
    
      return iterate(data);
    };
    
    const filterBySubstringKey2 = (data, value) => {
      const iterate = object => {
        return Object.entries(object).reduce((acc, [key, val]) => {
          if (typeof val === "object") {
            acc[key] = iterate(val);
          } else {
            if (key.toLowerCase().indexOf(value.toLowerCase()) !== -1) {
              acc[key] = val;
            }
          }
          return acc;
        }, {});
      };
    
      return iterate(data);
    };
    
    const filterBySubstringKey3 = (data, value) => {
      const iterate = object => {
        return Object.keys(object).reduce((acc, key) => {
          if (typeof object[key] === "object") {
            acc[key] = iterate(object[key]);
          } else {
            if (key.toLowerCase().indexOf(value.toLowerCase()) !== -1) {
              acc[key] = object[key];
            }
          }
          return acc;
        }, {});
      };
    
      return iterate(data);
    };
    
    const filterBySubstringKey4 = (data, value) => {
      const iterate = object => {
        let res = {};
        for (const key in object) {
          if (typeof object[key] === "object") {
            res[key] = iterate(object[key]);
          } else {
            if (key.toLowerCase().indexOf(value.toLowerCase()) !== -1) {
              res[key] = object[key];
            }
          }
        }
        return res;
      };
    
      return iterate(data);
    };
    

    【讨论】:

    • 您的版本将输出与 OP 代码不同的结果。 (1) 如果一个属性值为空,你的代码就会中断; (2)如果一个键匹配给定的值,但属性vale是一个对象(或null),你仍然会递归调用iterate,(3)你的iterate可以返回一个空对象。这不是简化,而是行为的改变。所以与原作的时间比较并没有真正的意义。
    猜你喜欢
    • 2016-11-03
    • 1970-01-01
    • 1970-01-01
    • 2019-09-15
    • 2017-07-18
    • 2021-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多