【问题标题】:Lodash Merge Two Arrays and categorize itLodash 合并两个数组并对其进行分类
【发布时间】:2019-12-06 01:12:12
【问题描述】:

我需要合并两个数组:类别和产品。每个产品都有一个类别对象。我需要按类别组织,包括类别对象并保留空类别。 GroupBy 函数只包含一个参数。

const Categories= [   
  {id: 1, 'name': 'category1'}
  {id: 2, 'name': 'category2'},
  {id: 3, 'name': 'category3'},
  {id: 4, 'name': 'category4'},    
]
const Products= [   
  {id: 1, 'name': 'product1', category: {id: 1, name: 'category1'}},
  {id: 2, 'name': 'product2', category: {id: 1, name: 'category1'}},
  {id: 3, 'name': 'product3', category: {id: 2, name: 'category2'}},
  {id: 4, 'name': 'product4', category: {id: 2, name: 'category2'}},    
]

预期结果

const result = [
  {
    category: {id: 1, name: 'category1'}, 
    products:[{id:1, name: 'produt1'}, {id: 2, name: 'produto1'} ]
  },
  {
    category: {id: 2, name: 'category2'}, 
    products:[{id:3, name: 'produt3'}, {id: 4, name: 'produto4'} ]
  },
  {
    category: {id: 3, name: 'category3'}, 
    products:[]
  },
 {
    category: {id: 4, name: 'category4'}, 
    products:[]
  },
]

尝试:

 for (i = 0; i < categoriesJson.length; i++) {
            categoriesJson[i] =   _.assign({}, categoriesJson[i], { products: [] })
            for (j = 0; j < productsJson.length; j++) {
                if(productsJson[j].categoryId.objectId === categoriesJson[i].objectId){
                    categoriesJson[i].products.push(productsJson[j])
                }
            }
        }

【问题讨论】:

  • 你到目前为止的努力?
  • 如果您的问题得到解答,请点击左侧的灰色复选标记accept one of the answersUse lodash groupBy function to categorize objects in an array
  • @trincot 这是一个稍微不同的问题。如果Products 没有类别,OP 想在输出中添加一个空的products 项目。但是,“太宽泛”我猜没有尝试
  • 我明白了。是的,反正太宽泛了。 “没有代码,没有答案”(让我想到“没有痛苦,没有收获”)。如果添加尝试,我将撤消我的近距离投票。
  • 我尝试了很多东西,你不知道。对于循环,从lodash分组,减少数组,我被这个问题困扰了好几天。 stackoverflow.com/questions/50840745/… 这个问题解决了我的问题,但给了我另一个问题:如何处理空类别。我将尝试编辑问题。抱歉,我是 lodash 和 stack 的新手。

标签: javascript arrays merge lodash


【解决方案1】:

如果解决方案中不需要 lodash,这就是我使用纯 javascript 的方式;

const Categories= [   
  {id: 1, 'name': 'category1'},
  {id: 2, 'name': 'category2'},
  {id: 3, 'name': 'category3'},
  {id: 4, 'name': 'category4'}    
];

const Products= [   
  {id: 1, 'name': 'product1', category: {id: 1, name: 'category1'}},
  {id: 2, 'name': 'product2', category: {id: 1, name: 'category1'}},
  {id: 3, 'name': 'product3', category: {id: 2, name: 'category2'}},
  {id: 4, 'name': 'product4', category: {id: 2, name: 'category2'}},    
];

const result = [];

for (let index in Categories) {
  let category_id = Categories[index].id;
  result.push({
    category: Categories[index],
    products: GetProductsWithCategoryId(category_id)
  }); 
}

function GetProductsWithCategoryId(category_id) {
  let products = [];
  for (let index in Products) {
    if (Products[index].category.id == category_id) {
      products.push({
        id: Products[index].id,
        name: Products[index].name
      });
    }
  }
  return products;
}

console.log("result:", result);

【讨论】:

    【解决方案2】:

    使用reduce,创建一个mappedProducts 对象,该对象基于category.idProducts 进行分组。像这样:

    {
      "1": [{ id: 1, name: "product1" }, { id: 2, name: "product2" }],
      "2": [{ id: 3, name: "product3" }, { id: 4, name: "product4" }]
    }
    

    然后,mapCategories 数组并获取每个 category 的输出

    const Categories=[{id:1,name:"category1"},{id:2,name:"category2"},{id:3,name:"category3"},{id:4,name:"category4"},],
          Products=[{id:1,name:"product1",category:{id:1,name:"category1"}},{id:2,name:"product2",category:{id:1,name:"category1"}},{id:3,name:"product3",category:{id:2,name:"category2"}},{id:4,name:"product4",category:{id:2,name:"category2"}}];
    
    const mappedProducts = Products.reduce((acc, { category, ...rest }) => {
      acc[category.id] = acc[category.id] || [];
      acc[category.id].push(rest)
      return acc;
    }, {})
    
    const output = Categories.map(category => ({
      category,
      products: mappedProducts[category.id] || []
    }))
    
    console.log(output)

    【讨论】:

      【解决方案3】:

      Categories(格式化为产品格式)连接到Products,按category.id分组,然后映射每个组-category取自第一项,而产品是分组中的项目,没有category,空项目被拒绝:

      const Products = [{"id":1,"name":"product1","category":{"id":1,"name":"category1"}},{"id":2,"name":"product2","category":{"id":1,"name":"category1"}},{"id":3,"name":"product3","category":{"id":2,"name":"category2"}},{"id":4,"name":"product4","category":{"id":2,"name":"category2"}}]
      const Categories = [{"id":1,"name":"category1"},{"id":2,"name":"category2"},{"id":3,"name":"category3"},{"id":4,"name":"category4"}]
      
      const result = _(Products)
        .concat(Categories.map(category => ({ category })))
        .groupBy('category.id')
        .map(group => ({
          category: _.head(group).category,
          products: _(group)
            .map(o => _.omit(o, 'category'))
            .reject(_.isEmpty)
            .value()
        }))
        .value()
      
      console.log(result)
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"&gt;&lt;/script&gt;

      lodash/fp 也是同样的想法。用_.useWith() 函数包装_.flow(),并预先格式化Categories(第二个参数)以适应Categories。其余的类似于lodash链。

      const { useWith, identity, flow, concat, groupBy, map, head, omit, reject, isEmpty } = _
      
      const formatProducts = flow(map(omit('category')), reject(isEmpty))
      
      const fn = useWith(flow(
        concat,
        groupBy('category.id'),
        map(group => ({
          category: head(group).category,
          products: formatProducts(group)
        }))
      ), [identity, map(category => ({ category }))])
      
      const Products = [{"id":1,"name":"product1","category":{"id":1,"name":"category1"}},{"id":2,"name":"product2","category":{"id":1,"name":"category1"}},{"id":3,"name":"product3","category":{"id":2,"name":"category2"}},{"id":4,"name":"product4","category":{"id":2,"name":"category2"}}]
      const Categories = [{"id":1,"name":"category1"},{"id":2,"name":"category2"},{"id":3,"name":"category3"},{"id":4,"name":"category4"}]
      
      const result = fn(Products, Categories)
      
      console.log(result)
      &lt;script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'&gt;&lt;/script&gt;

      【讨论】:

        【解决方案4】:

        在单个函数中。不需要 Lodash:

        const Categories = [
          { id: 1, name: "category1" },
          { id: 2, name: "category2" },
          { id: 3, name: "category3" },
          { id: 4, name: "category4" }
        ];
        const Products = [
          { id: 1, name: "product1", category: { id: 1, name: "category1" } },
          { id: 2, name: "product2", category: { id: 1, name: "category1" } },
          { id: 3, name: "product3", category: { id: 2, name: "category2" } },
          { id: 4, name: "product4", category: { id: 2, name: "category2" } }
        ];
        
        function combine(categories, products) {
          return categories.reduce((list, category) => {
            const nextItem = {
              category,
              products: [
                products.filter(p => p.category.id === category.id).map(
                  ({ id, name }) => ({
                    id,
                    name
                  })
                )
              ]
            };
            list.push(nextItem);
            return list;
          }, []);
        }
        
        const result = combine(Categories, Products)
        

        现在供您参考,如果您有大量类别和/或产品列表,这将不是理想的解决方案,因为其中涉及很多循环。相反,您将以一种只需要查看给定产品一次的方式缓存产品(而不是查看每个类别的每个产品)。对于小数据集,这种优化不是必需的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-10-06
          • 2021-12-10
          • 2017-06-08
          • 1970-01-01
          • 2021-04-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多