英文:
Group into nested array of objects in Javascript
问题
{
"我有一个类别数组:[\n { categoryId: '01', categoryName: 'Byggmaterial' },\n { categoryId: '010', categoryName: 'Bindemedel och bruk' },\n { categoryId: '01001', categoryName: 'Cement' },\n { categoryId: '01002', categoryName: 'Bruksbindemedel' },\n { categoryId: '01003', categoryName: 'Kalkvaror' },\n { categoryId: '011', categoryName: 'Byggnadsblock och ballast' },\n { categoryId: '01101', categoryName: 'Betongblock' },\n { categoryId: '01102', categoryName: 'Tegel' },\n { categoryId: '02', categoryName: 'Byggmaterial' },\n { categoryId: '020', categoryName: 'Bindemedel och bruk' },\n { categoryId: '02001', categoryName: 'Cement' },\n { categoryId: '02002', categoryName: 'Bruksbindemedel' }\n......\n]\n\n和一个产品数组:[\n {\n productNumber: '01405',\n productName: 'SERVALAC AQUA BLANK - Utgått'\n },\n {\n productNumber: '01405',\n productName: 'SERVALAC AQUA HALVBLANK - Utgått'\n },\n {\n productNumber: '03405',\n productName: 'SERVALAC AQUA HALVBLANK - Utgått'\n },\n { productNumber: '03404', productName: 'SCOTTE GT-20 - UTGÅTT' },\n { productNumber: '03404', productName: 'SCOTTE 7 - UTGÅTT' },\n { productNumber: '03404', productName: 'SCOTTE 7 - UTGÅTT' },\n { productNumber: '03404', productName: 'SCOTTE 7 - UTGÅTT' },\n { productNumber: '03404', productName: 'SCOTTE 5 - UTGÅTT' },\n { productNumber: '03404', productName: 'SCOTTE 20 - UTGÅTT' }\n......\n]\n\n我想将每个产品分组到相应的类别中。\n类别也应该像这样分组:主类别(所有两位数的类别),第二类别(三位数的类别)和下一个类别(五位数的类别)。\n每个产品应该添加到相应的主类别、第二类别和第三类别。\n\n结果应该如下所示:\n\n{\n "id":"01",\n "categoryName":"Byggmaterial",\n "items":[\n {\n "id":"010",\n "categoryName":"Bindemedel och bruk",\n "items": [\n {\n "id":"01001",\n "categoryName":"Cement",\n "products": [\n {\n "productNumber":"01001",\n "productName":"Tunnfog och Tunnputsbruk A"\n },\n {\n "productNumber":"01001",\n "productName":"Tunnfog"\n },\n .......\n ]\n }\n ]\n }\n ]\n}\n\n\n我被卡住了,所以我需要帮助。\n我尝试使用“for循环”嵌套“for循环”,但我只成功地将所有产品分组到主类别中。\n\n{...}
}
英文:
I have an array of categories:
[
{ categoryId: '01', categoryName: 'Byggmaterial' },
{ categoryId: '010', categoryName: 'Bindemedel och bruk' },
{ categoryId: '01001', categoryName: 'Cement' },
{ categoryId: '01002', categoryName: 'Bruksbindemedel' },
{ categoryId: '01003', categoryName: 'Kalkvaror' },
{ categoryId: '011', categoryName: 'Byggnadsblock och ballast' },
{ categoryId: '01101', categoryName: 'Betongblock' },
{ categoryId: '01102', categoryName: 'Tegel' },
{ categoryId: '02', categoryName: 'Byggmaterial' },
{ categoryId: '020', categoryName: 'Bindemedel och bruk' },
{ categoryId: '02001', categoryName: 'Cement' },
{ categoryId: '02002', categoryName: 'Bruksbindemedel' }
......
]
And an array of products:
[
{
productNumber: '01405',
productName: 'SERVALAC AQUA BLANK - Utg�tt'
},
{
productNumber: '01405',
productName: 'SERVALAC AQUA HALVBLANK - Utg�tt'
},
{
productNumber: '03405',
productName: 'SERVALAC AQUA HALVBLANK - Utg�tt'
},
{ productNumber: '03404', productName: 'SCOTTE GT-20 - UTG�TT' },
{ productNumber: '03404', productName: 'SCOTTE 7 - UTG�TT' },
{ productNumber: '03404', productName: 'SCOTTE 7 - UTG�TT' },
{ productNumber: '03404', productName: 'SCOTTE 7 - UTG�TT' },
{ productNumber: '03404', productName: 'SCOTTE 5 - UTG�TT' },
{ productNumber: '03404', productName: 'SCOTTE 20 - UTG�TT' },
......
]
I want to group each product in the corresponding category.
The categories should be also grouped like this: main category (all the categories with 2 digits), second category (with 3 digits) and the next one (with 5 digits).
Each product should be added to the corresponding main category, second and third category.
The result should be like this:
{
"id":"01",
"categoryName":"Byggmaterial",
"items":[
{
"id":"010",
"categoryName":"Bindemedel och bruk",
"items": [
{
"id":"01001",
"categoryName":"Cement",
"products": [
{
"productNumber":"01001",
"productName":"Tunnfog och Tunnputsbruk A"
},
{
"productNumber":"01001",
"productName":"Tunnfog"
},
.......
]
}
]
},
I'm stuck so I need help.
I've tried with "for loop" inside "for loop", but I only succeeded to group all the products in main category.
{"id":"01","categoryName":"Byggmaterial","items":[{"productNumber":"01001","productName":"Tunnfog och Tunnputsbruk A"},{"productNumber":"01001","productName":"Lagningsmassa fin"},{"productNumber":"01399","productName":"Golvfoam Premium MFR"}, {"productNumber":"01199","productName":"THERMOMUR 350 STD SLUTET"}, {"productNumber":"01701","productName":"Adva Flow 484"},{"productNumber":"01706","productName":"Pieri Decobio C-23"}
Is there any other solution then "for loop"? I think that I cannot get the wanted result with only for loop.
Thank you in advance!
答案1
得分: 1
你可以使用两个相互递归的辅助函数:一个用于选择给定类别的子类别:
function items(cid, level) {
return categories
.filter(c => c.categoryId.startsWith(cid) && c.categoryId.length === level)
.map(process)
}
以及一个用于处理类别的函数:
function process(cat) {
let cid = cat?.categoryId || ''
switch (cid.length) {
case 0:
return {...cat, items: items(cid, 2)}
case 2:
return {...cat, items: items(cid, 3)}
case 3:
return {...cat, items: items(cid, 5)}
case 5:
return {
...cat,
products: products.filter(p => p.productNumber.startsWith(cid))
}
}
}
最后,只需无参数调用 process()
。
英文:
You can use two mutually recursive helper functions: one that selects subcategories for the given category:
function items(cid, level) {
return categories
.filter(c => c.categoryId.startsWith(cid) && c.categoryId.length === level)
.map(process)
}
and one that processes a category:
function process(cat) {
let cid = cat?.categoryId || ''
switch (cid.length) {
case 0:
return {...cat, items: items(cid, 2)}
case 2:
return {...cat, items: items(cid, 3)}
case 3:
return {...cat, items: items(cid, 5)}
case 5:
return {
...cat,
products: products.filter(p => p.productNumber.startsWith(cid))
}
}
}
Finally, just invoke process()
with no arguments.
答案2
得分: 1
你可以通过保留指向"items"的所有"categoryId"来构建目录,然后将产品添加到相应的类别中。
英文:
You could build the catalog by preserving all categoryId
which points to items
and later push the products to the category.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const
categories = [{ categoryId: '01', categoryName: 'Byggmaterial' }, { categoryId: '010', categoryName: 'Bindemedel och bruk' }, { categoryId: '01001', categoryName: 'Cement' }, { categoryId: '01002', categoryName: 'Bruksbindemedel' }, { categoryId: '01003', categoryName: 'Kalkvaror' }, { categoryId: '011', categoryName: 'Byggnadsblock och ballast' }, { categoryId: '01101', categoryName: 'Betongblock' }, { categoryId: '01102', categoryName: 'Tegel' }, { categoryId: '02', categoryName: 'Byggmaterial' }, { categoryId: '020', categoryName: 'Bindemedel och bruk' }, { categoryId: '02001', categoryName: 'Cement' }, { categoryId: '02002', categoryName: 'Bruksbindemedel' }],
products = [{ productNumber: "01001", productName: "Tunnfog och Tunnputsbruk A" }, { productNumber: "01001", productName: "Tunnfog" }],
catalog = categories.reduce((r, { categoryId, categoryName }) => {
let i = categoryId.length;
do {
const key = categoryId.slice(0, i);
if (key in r) {
(r[key].items ??= []).push(r[categoryId] = { categoryId, categoryName });
return r;
}
} while (--i)
r.items.push(r[categoryId] = { categoryId, categoryName });
return r;
}, { items: [] });
products.forEach(o => (catalog[o.productNumber].product ??= []).push(o));
console.log(catalog.items);
<!-- language: lang-css -->
.as-console-wrapper { max-height: 100% !important; top: 0; }
<!-- end snippet -->
答案3
得分: 0
Here is the translated code snippet without the code comments:
function hierarchy(categories, products) {
function parent(s) {
while (!map.has(s)) s = s.slice(0, -1);
return map.get(s);
}
const root = { items: [] };
const map = new Map(categories.map(({categoryId: id, ...rest}) => [id, { id, ...rest }])).set("", root);
for (const cat of categories) {
(parent(cat.categoryId.slice(0, -1)).items ??= []).push(map.get(cat.categoryId));
}
for (const prod of products) {
(parent(prod.productNumber).products ??= []).push(prod);
}
return root.items;
}
// Demo
const categories = [
{ categoryId: '01', categoryName: 'Building Materials' },
{ categoryId: '010', categoryName: 'Binders and Mortars' },
{ categoryId: '01001', categoryName: 'Cement' },
{ categoryId: '01002', categoryName: 'Mortars' },
{ categoryId: '01003', categoryName: 'Lime Products' },
{ categoryId: '011', categoryName: 'Building Blocks and Aggregate' },
{ categoryId: '01101', categoryName: 'Concrete Blocks' },
{ categoryId: '01102', categoryName: 'Brick' },
{ categoryId: '02', categoryName: 'Building Materials' },
{ categoryId: '020', categoryName: 'Binders and Mortars' },
{ categoryId: '02001', categoryName: 'Cement' },
{ categoryId: '02002', categoryName: 'Mortars' }
];
const products = [
{ productNumber: '01001', productName: 'Thin Joints and Thin Plaster Mortar A' },
{ productNumber: '01001', productName: 'Thin Joints' },
];
const forest = hierarchy(categories, products);
console.log(forest);
This code snippet has been translated.
英文:
If product numbers can be longer than category numbers, then maybe also look up the category iteratively:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
function hierarchy(categories, products) {
function parent(s) {
while (!map.has(s)) s = s.slice(0, -1);
return map.get(s);
}
const root = { items: [] };
const map = new Map(categories.map(({categoryId: id, ...rest}) => [id, { id, ...rest }])).set("", root);
for (const cat of categories) {
(parent(cat.categoryId.slice(0, -1)).items ??= []).push(map.get(cat.categoryId));
}
for (const prod of products) {
(parent(prod.productNumber).products ??= []).push(prod);
}
return root.items;
}
// Demo
const categories = [
{ categoryId: '01', categoryName: 'Byggmaterial' },
{ categoryId: '010', categoryName: 'Bindemedel och bruk' },
{ categoryId: '01001', categoryName: 'Cement' },
{ categoryId: '01002', categoryName: 'Bruksbindemedel' },
{ categoryId: '01003', categoryName: 'Kalkvaror' },
{ categoryId: '011', categoryName: 'Byggnadsblock och ballast' },
{ categoryId: '01101', categoryName: 'Betongblock' },
{ categoryId: '01102', categoryName: 'Tegel' },
{ categoryId: '02', categoryName: 'Byggmaterial' },
{ categoryId: '020', categoryName: 'Bindemedel och bruk' },
{ categoryId: '02001', categoryName: 'Cement' },
{ categoryId: '02002', categoryName: 'Bruksbindemedel' }
];
const products = [
{ productNumber: '01001', productName: 'Tunnfog och Tunnputsbruk A' },
{ productNumber: '01001', productName: 'Tunnfog' },
];
const forest = hierarchy(categories, products);
console.log(forest);
<!-- end snippet -->
答案4
得分: 0
你可以像这样做:
const getNextPrefixLength = (prefix) =>
// Needed because level 3 has 5 chars
prefix.length + (prefix.length === 3 ? 2 : 1);
const getCategoriesByPrefix = (idPrefix) =>
categories.filter(
({ categoryId }) =>
categoryId.length === getNextPrefixLength(idPrefix) &&
categoryId.startsWith(idPrefix)
);
const getGroupedCategoryRecursively = ({ categoryId: id, categoryName }) => ({
id,
categoryName,
items: getCategoriesByPrefix(id).map(getGroupedCategoryRecursively),
});
const result = getCategoriesByPrefix("0").map(getGroupedCategoryRecursively);
英文:
You could do it something like this:
const getNextPrefixLength = (prefix) =>
// Needed because level 3 has 5 chars
prefix.length + (prefix.length === 3 ? 2 : 1);
const getCategoriesByPrefix = (idPrefix) =>
categories.filter(
({ categoryId }) =>
categoryId.length === getNextPrefixLength(idPrefix) &&
categoryId.startsWith(idPrefix)
);
const getGroupedCategoryRecursively = ({ categoryId: id, categoryName }) => ({
id,
categoryName,
items: getCategoriesByPrefix(id).map(getGroupedCategoryRecursively),
});
const result = getCategoriesByPrefix("0").map(getGroupedCategoryRecursively);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论