【问题标题】:What is a more machine efficient way than for loop + lodash combo?有什么比 for loop + lodash 组合更高效的方法?
【发布时间】:2019-10-23 15:33:12
【问题描述】:

更新:编辑代码以获得更清晰的解释。

我需要根据另一个属性数组在一个数组中找到 x 个对象,我将使用 for 循环 + lodash.filter 来检索列表。我想知道 NodeJs 是单线程的,它怎么能更有效。一个示例用例是减少 mysql 调用的数量。例如,我有一个产品列表,我想通过他们的产品类别检索一个子集。所以我会得到这样的东西:

const lodash = require('lodash');
...
let productCategories = [{id:111,...},{id:222,...},{id:333,...},{id:444,...}];
let products = await this.getProductByProductCategories(lodash.map(productCategories,'id')); //Does mysql call whereIn ... which I will not include here.

for(let productCategory of productCategories){
    let productSubset = lodash.filter(products, {product_category_id: productCategory.id};
     //Do something with productSubset
     //I also want to reference the parent object here: productCategory.xxx
}

有没有更有效(和代码友好)的方式来执行 for 循环 + lodash.filter 组合?

【问题讨论】:

    标签: javascript node.js lodash


    【解决方案1】:

    不需要在 for 循环中进行过滤。您需要改用_.groupBy

    例如

    ...
    const productSubsets = _.groupBy(products, 'product_category_id');
    for (let key in productSubsets) {
      // do something with productSubsets[key]
    }
    

    【讨论】:

    • 不幸的是,如果我想引用数组中的对象,这将不起作用。
    【解决方案2】:

    如果你想坚持使用 lodash,你可以使用 _.groupBy 并稍后对产生的对象的值做一些事情:

    const productsByCategoryId = _.groupBy(products, 'product_category_id');
    

    您可以检索值(例如,使用 lodash 的 _.values())或使用 _.mapValues() 映射它,或者只使用纯 JavaScript 来访问您需要的数据。

    它更优雅,但可能不是真的更快。如果你想在异步环境中更高效,也许你应该尝试像这样的反应:

    from(products)
      .pipe(
        groupBy(product => product.product_category_id),
        //do something in pipe 
      )
    

    更多信息:https://www.learnrxjs.io/operators/transformation/groupby.html

    【讨论】:

      【解决方案3】:

      不确定lodash 在底层做了什么,但像这样的嵌套 for 循环通常需要O(n^2) 时间;但是,使用哈希映射,您可以将其减少到 O(n) 时间,例如

      const productCategoryIds = [111,222,333,444,555];
      const mappedProductCategoryIds = productCategoryIds.reduce((obj, id) => {
          obj[id] = true;
          return obj;
      }, {});
      
      const products = await this.getProductByProductCategories(productCategoryIds); //Does mysql call whereIn ... which I will not include here.
      
      const productSubset = products.filter(product => mappedProductCategoryIds[product.product_category_id]);
      
      //Do something with productSubset
      

      我们首先遍历 productCategoryIds 并创建一个哈希映射 (mappedProductCategoryIds),我们可以根据它测试任何 productproduct_category_id,只需检查键 product_category_id 的值是否在该哈希映射mappedProductCategoryIdstruthy(即它是true)还是falsey(即undefined)。 (哈希映射查找需要O(1) 时间。)

      如果mappedProductCategoryIds 包含其product_category_id,JavaScript filter() 将收集product;否则,它将拒绝它。

      【讨论】:

        【解决方案4】:

        取决于您希望如何准确使用子集,但您可以考虑从数据库返回一组有序的产品

        function doSomethingWithProductSubset(productSubset) {
            // do something with product subset
            console.dir(productSubset);
        }
        const productCategoryIds = [111,222,333,444,555];
        const products = await getProductByProductCategoriesOrderedByCategory(productCategoryIds);
        if (products && products.length) {
            let productSubset = [];
            let category = products[0].category;
            products.forEach(product => {
                if (productSubset.length && product.category != category) {
                    doSomethingWithProductSubset(productSubset);
                    productSubset = [];
                    category = product.category;
                }
                productSubset.push(product);
            });
            if (productSubset.length) doSomethingWithProductSubset(productSubset);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-30
          • 2014-06-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多