【问题标题】:Javascript transform flat data to nested objectJavascript 将平面数据转换为嵌套对象
【发布时间】:2019-05-14 05:11:56
【问题描述】:

我对 react/ES6 很陌生,当我使用 reduce 方法将我从 API 接收到的平面数组转换为嵌套对象时,我遇到了一个奇怪的行为。 我已经熟悉 map 和 filter,但之前从未使用过 reduce。

我很确定我用错了,但它是这样的。

我有以下平面数据集:

[
  {
    category:"Category1",
    subCategory:"SubCategory1",
    productType:"ProductType1",
    brand:"brand1"
  },
  {
    category:"Category1",
    subCategory:"SubCategory2",
    productType:"ProductType2",
    brand:"brand2"
  },
  {
    category:"Category1",
    subCategory:"SubCategory2",
    productType:"ProductType2",
    brand:"brand3"
  },
  {
    category:"Category2",
    subCategory:"SubCategory1",
    productType:"ProductType1",
    brand:"brand1"
  },
  {
    category:"Category2",
    subCategory:"SubCategory1",
    productType:"ProductType2",
    brand:"brand2"
  }
]

我正在使用以下代码从平面数据集中获取嵌套对象。

getNestedData() {
  var baseData = this.getBaseData();

  return baseData.reduce((categories,category) => {
    if(!categories[category.category]){
      categories[category.category] = {
        category: category.category,
        subCategories: baseData.filter(bd => bd.category === category.category)
          .reduce((subCategories,subCategory) => {
            if(!subCategories[subCategory.subCategory]) {
              subCategories[subCategory.subCategory] = {
                subCategory: subCategory.subCategory,
                productTypes: baseData.filter(bd => bd.category === subCategory.category && bd.subCategory === subCategory.subCategory)
                  .reduce((productTypes,productType) => {
                    if(!productTypes[productType.productType]) {
                      productTypes[productType.productType] = {
                        productType: productType.productType,
                        brands: baseData.filter(bd => bd.category === productType.category && bd.subCategory === productType.subCategory && bd.productType === productType.productType)
                          .reduce((brands,brand) => {
                            if(!brands[brand.brand]) {
                              brands[brand.brand] = {
                                brand: brand.brand
                              }
                            }
                            return brands;
                          }) 
                      };
                    }
                    return productTypes;
                  })
              };
            }
            return subCategories;
          })
      }
    }
    return categories;
  });
}

但是,结果不是我所期望的。它返回数组第一个类别内的根数组对象。喜欢Category1 => [Category1,Category2]。如果你进入 category1 孩子,同样的事情也会发生。

我准备了以下jsFiddle 来显示我的问题。

让我知道我做错了什么我在谷歌上搜索了几个小时。我也想知道这种方式是否最有效?

编辑:

有一个预期输出的例子:

[
  {
    category: "Category1"
    subCategories:[
      {
        subCategory:"SubCategory1",
        productTypes:[
          {
            productType:"ProductType1",
            brands:["Brand1"]    
          }
        ]   
      },
      {
        subCategory:"SubCategory2",
        productTypes:[
          {
            productType:"ProductType2",
            brands:["Brand2","Brand3"]
          }   
        ]
      }
    ]
  },
  {
    category: "Category2",
    subCategories:[
      {
        subCategory:"SubCategory1",
        productTypes:[
          {
            productType:"ProductType1",
            brands:["Brand1"]
          },
          {
            productType:"ProductType2",
            brands:["Brand2"]
          }
        ]
      }
    ]
  }
]

编辑

Mat 是对的,我在使用 reduce 时忘记传递初始值。正如我预期的那样,传递初始值使减少工作。然后我就能够更改我的代码以获得预期的结果。代码不是最优雅但运行良好:

getNestedData()
{
    var baseData = this.getBaseData();
  return baseData
  .map(c => {return c.category;})
  .reduce((categories,category) => {
  var currentCategory = categories.filter(
    c => c.category === category
  );
    if (currentCategory.length === 0) {
            var categoryData = baseData.filter(bd => bd.category === category);
      categories.push({
        category:category,
        subCategories: categoryData
        .map(c => {return c.subCategory})
        .reduce((subCategories,subCategory) => {
            var currentSubCategory = subCategories.filter(sc => sc.subCategory === subCategory)
            if(currentSubCategory.length === 0)
          {
            var subCategoryData = categoryData.filter(cd => cd.subCategory === subCategory);
            subCategories.push({
                subCategory:subCategory,
              productTypes: subCategoryData
              .map(scd => {return scd.productType})
              .reduce((productTypes,productType) => {
                var currentproductType = productTypes.filter(pt => pt.productType === productType);
                if(currentproductType.length === 0)
                {
                    var productTypeData = subCategoryData.filter(scd => scd.productType === productType)
                  productTypes.push({
                    productType:productType,
                    brands: productTypeData
                    .map(ptd => {return ptd.brand})
                    .reduce((brands,brand) => {
                        var currentBrand = brands.filter(b => b.brand === brand);
                      if(currentBrand.length === 0)
                      {
                        brands.push({brand:brand});
                      }
                      return brands;
                    },[])
                  });
                }
                return productTypes;
              },[])
            });
          }
          return subCategories;
        },[])
      });
    }
    return categories;
  },[])
}

There 是具有预期行为的工作 jsFiddle。

【问题讨论】:

  • 你能举一个预期输出的例子吗?
  • 更新你的问题有预期的结果,否则将被提名为“不清楚问什么”,学会正确解释你的需求
  • 如果这足够清楚,请告诉我

标签: javascript arrays reactjs ecmascript-6 reduce


【解决方案1】:

所以看起来您正在尝试对数组数据进行非规范化。您的大量嵌套函数难以阅读,我认为如果您使用 lodash 的 set 函数,您可以更轻松地完成您想要的事情。例如:

const data = [
  {
    category:"Category1",
    subCategory:"SubCategory1",
    productType:"ProductType1",
    brand:"brand1"
  },
  {
    category:"Category1",
    subCategory:"SubCategory2",
    productType:"ProductType2",
    brand:"brand2"
  },
  {
    category:"Category1",
    subCategory:"SubCategory2",
    productType:"ProductType2",
    brand:"brand3"
  },
  {
    category:"Category2",
    subCategory:"SubCategory1",
    productType:"ProductType1",
    brand:"brand1"
  },
  {
    category:"Category2",
    subCategory:"SubCategory1",
    productType:"ProductType2",
    brand:"brand2"
  }
]

const result = data.reduce((output, item) => {
  _.set(output, `${item.category}.subCategories.${item.subCategory}.productTypes.${item.productType}.brands.${item.brand}.brand`, item.brand)
  return output
}, {})

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

您的代码不起作用(忽略错别字)的原因是我认为您忘记为reduce 函数提供初始值。查看最后一个可选参数here

【讨论】:

  • 我明天早上试试。谢谢!我在原始帖子中添加了预期的输出。你的解决方案会给我这个输出吗?
  • 那里有一个按钮,上面写着“运行代码 sn-p”。寻找自己
  • 不,我的解决方案不会为您提供更新问题的输出。不可能推断出您希望子类型是数组。这使得解决方案比我提供的更困难。
猜你喜欢
  • 1970-01-01
  • 2016-11-16
  • 2020-01-15
  • 1970-01-01
  • 2016-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多