简体   繁体   English

基于属性合并两个数组

[英]Merging two arrays based on Property

I have two arrays: one contains categories and the second contains items. 我有两个数组:一个包含类别,第二个包含项目。

I would like to merge the all items items into their proper category array using lodash. 我想使用lodash将所有项目项合并到其适当的类别数组中。 However, I do have a question. 但是,我确实有一个问题。 Since this can be done with a double foreach loop, is there any reason to use lodash? 由于这可以通过双foreach循环完成,因此有没有理由使用lodash?

Array 1 (categories): 数组1(类别):

"categories": [
    {
        "id": 1,
        "name": "cat_1",
        "items": []
    },
    {
        "id": 11,
        "name": "cat_2",
        "items": []
    },
    {
        "id": 61,
        "name": "cat_3",
        "items": []
    }
]

Array 2 (contains items): 数组2(包含项):

[ 
    { 
        id: 15,
        name: 'some_item',
        category_id: 1,
        category_name: 'cat_1',
    },
    { 
        id: 112,
        name: 'some_item',
        category_id: 11,
        category_name: 'cat_2',
    },
    { 
        id: 235,
        name: 'some_item',
        category_id: 11,
        category_name: 'cat_2',
    },

]

The desired object would look: 所需的对象将如下所示:

"categories": 
    [
        {
            "id": 1,
            "name": "cat_1",
            "items": [
                { 
                    id: 15,
                    name: 'some_item',
                    category_id: 1,
                    category_name: 'cat_1',
                }
            ]
        },
        {
            "id": 11,
            "name": "cat_2",
            "items": [
                { 
                    id: 112,
                    name: 'some_item',
                    category_id: 11,
                    category_name: 'cat_2',
                },
                { 
                    id: 235,
                    name: 'some_item',
                    category_id: 11,
                    category_name: 'cat_2',
                }
            ]
        },
        {
            "id": 61,
            "name": "cat_3",
            "items": []
        }
    ]

This is how you'd do it with plain ES5: 这是使用普通ES5的方法:

 const categories = [{id:1,name:"cat_1",items:[]},{id:11,name:"cat_2",items:[]},{id:61,name:"cat_3",items:[]}] const items = [{id:15,name:"some_item",category_id:1,category_name:"cat_1"},{id:112,name:"some_item",category_id:11,category_name:"cat_2"},{id:235,name:"some_item",category_id:11,category_name:"cat_2"}]; const result = categories.map(c => ({ ...c, items: items.filter(i => i.category_id === c.id) })); console.log(result); 

Javascript is a very special language because of it's history. 由于Java的历史,它是一种非常特殊的语言。 It started as a very humble language with little features, and although it has evolved, not all of it's features are supported by all browsers. 它最初是一种非常不起眼的语言,几乎没有任何功能,尽管它已经发展了,但并非所有浏览器都支持所有功能。

This caused the apparition of libraries like lodash, underscore, inmutable.js, and jquery, which came to fill the gap in Javascript's standard library. 这引起了像lodash,underscore,inmutable.js和jquery之类的库的出现,从而填补了Javascript标准库中的空白。

As you see though, now JS has very convenient abstractions like each , map , find , filter and reduce , which are universally understood concepts across languages. 如您所见,现在JS具有非常方便的抽象,例如eachmapfindfilterreduce ,它们是跨语言的普遍理解的概念。 This makes code much more understandable than when you write low-level, procedural code using for loops. 与使用for循环编写低级的过程代码相比,这使代码更易于理解。

As a color note, I've started programming with ruby, which is known for having a standard library rich in collection abstractions . 作为一个颜色说明,我开始使用ruby进行编程,它以拥有丰富的集合抽象标准库而闻名。 As a result, I did not notice there where for loops in the language until very recently, even when they are necessary to implement the higher level abstractions. 结果,直到最近,我才注意到语言中的for循环在哪里,即使实现高层抽象是必要的。

I have never used lodash, but you're right, this could be quite easily done with a foreach loop. 我从未使用过lodash,但是您是对的,可以使用foreach循环轻松完成此操作。 Not even a double foreach loop, a single one with a '.find' or '.filter' 甚至没有两个foreach循环,只有一个带有'.find'或'.filter'的循环

(a) loop through each item and use array.find to find the appropriate category, and input the item into the category (a)遍历每个项目并使用array.find查找合适的类别,然后将项目输入到类别中

(b) loop through each category and use array.filter to find the appropriate items, and input those items into each category. (b)遍历每个类别,并使用array.filter查找适当的项目,然后将这些项目输入每个类别。

Here's one option laid out: 这是一种选择:

(()=>{
  const categories = [{
      "id": 1,
      "name": "cat_1",
      "items": []
    },
    {
      "id": 11,
      "name": "cat_2",
      "items": []
    },
    {
      "id": 61,
      "name": "cat_3",
      "items": []
    }]

  const items = [{ 
      id: 15,
      name: 'some_item',
      category_id: 1,
      category_name: 'cat_1',
    },
    { 
      id: 112,
      name: 'some_item',
      category_id: 11,
      category_name: 'cat_2',
    },
    { 
      id: 235,
      name: 'some_item',
      category_id: 11,
      category_name: 'cat_2',
    }]

  categories.forEach((cat) => {
    cat.items = items.filter((item) => item.category_id === cat.id);
  })
})()

You can group the items by the category id using lodash _.keyBy() , and then loop the categories with Array#map , and create new categories objects, with the items takes from itemsByCategory : 您可以使用lodash _.keyBy()按类别ID对项目进行分组,然后使用Array#map循环类别,并创建新的类别对象,其中项目取自itemsByCategory

 const categories = [{"id":1,"name":"cat_1","items":[]},{"id":11,"name":"cat_2","items":[]},{"id":61,"name":"cat_3","items":[]}]; const items = [{"id":15,"name":"some_item","category_id":1,"category_name":"cat_1"},{"id":112,"name":"some_item","category_id":11,"category_name":"cat_2"},{"id":235,"name":"some_item","category_id":11,"category_name":"cat_2"}]; const itemsByCategory = _.groupBy(items, 'category_id'); const categoriesWithItems = categories.map(({ id, name, items }) => ({ id, name, items: items.concat(itemsByCategory[id]) })); console.log(categoriesWithItems); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script> 

As you can see, the only lodash method I've used is _.keyBy() , which we can replace with Array#reduce : 如您所见,我使用的唯一lodash方法是_.keyBy() ,我们可以将其替换为Array#reduce

 const categories = [{"id":1,"name":"cat_1","items":[]},{"id":11,"name":"cat_2","items":[]},{"id":61,"name":"cat_3","items":[]}]; const items = [{"id":15,"name":"some_item","category_id":1,"category_name":"cat_1"},{"id":112,"name":"some_item","category_id":11,"category_name":"cat_2"},{"id":235,"name":"some_item","category_id":11,"category_name":"cat_2"}]; const itemsByCategory = items.reduce((r, item) => { r[item.category_id] = item; return r; }, {}); const categoriesWithItems = categories.map(({ id, name, items }) => ({ id, name, items: items.concat(itemsByCategory[id]) })); console.log(categoriesWithItems); 

So, using lodash is a matter of convenience mostly. 因此,使用lodash主要是为了方便。 Since lodash is written in JS, you can create anything that lodash do by using JS (and ES6 makes life even easier), and it saves some bundle size. 由于lodash是用JS编写的,因此您可以使用JS创建lodash所做的任何事情(ES6使工作更轻松),并且可以节省一些捆绑包的大小。 However, lodash does may save lots of handwritten purely tested code, which reinvents the wheel. 但是,lodash确实可以节省大量手写的,经过纯测试的代码,从而重新发明了轮子。 I suggest using lodash-es instead of lodash, since the es version is modular, and you can import just what you need. 我建议使用lodash-es而不是lodash,因为es版本是模块化的,因此您可以导入所需的内容。 This balances the ease of use, with the bundle size. 这可以在易用性和捆束尺寸之间取得平衡。

You could take a Map for the categories and then iterate items for pushing to the corresponding category. 您可以为类别选择一个Map ,然后迭代项目以推送到相应的类别。

 var object = { categories: [{ id: 1, name: "cat_1", items: [] }, { id: 11, name: "cat_2", items: [] }, { id: 61, name: "cat_3", items: [] }] }, items = [{ id: 15, name: 'some_item', category_id: 1, category_name: 'cat_1', }, { id: 112, name: 'some_item', category_id: 11, category_name: 'cat_2', }, { id: 235, name: 'some_item', category_id: 11, category_name: 'cat_2', }], map = new Map(object.categories.map(category => [category.id, category.items])); items.forEach(item => map.get(item.category_id).push(item)); console.log(object); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM