在JavaScript中将分组为嵌套对象数组。

huangapple go评论104阅读模式
英文:

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:

  1. [
  2. { categoryId: '01', categoryName: 'Byggmaterial' },
  3. { categoryId: '010', categoryName: 'Bindemedel och bruk' },
  4. { categoryId: '01001', categoryName: 'Cement' },
  5. { categoryId: '01002', categoryName: 'Bruksbindemedel' },
  6. { categoryId: '01003', categoryName: 'Kalkvaror' },
  7. { categoryId: '011', categoryName: 'Byggnadsblock och ballast' },
  8. { categoryId: '01101', categoryName: 'Betongblock' },
  9. { categoryId: '01102', categoryName: 'Tegel' },
  10. { categoryId: '02', categoryName: 'Byggmaterial' },
  11. { categoryId: '020', categoryName: 'Bindemedel och bruk' },
  12. { categoryId: '02001', categoryName: 'Cement' },
  13. { categoryId: '02002', categoryName: 'Bruksbindemedel' }
  14. ......
  15. ]

And an array of products:

  1. [
  2. {
  3. productNumber: '01405',
  4. productName: 'SERVALAC AQUA BLANK - Utgtt'
  5. },
  6. {
  7. productNumber: '01405',
  8. productName: 'SERVALAC AQUA HALVBLANK - Utgtt'
  9. },
  10. {
  11. productNumber: '03405',
  12. productName: 'SERVALAC AQUA HALVBLANK - Utgtt'
  13. },
  14. { productNumber: '03404', productName: 'SCOTTE GT-20 - UTGTT' },
  15. { productNumber: '03404', productName: 'SCOTTE 7 - UTGTT' },
  16. { productNumber: '03404', productName: 'SCOTTE 7 - UTGTT' },
  17. { productNumber: '03404', productName: 'SCOTTE 7 - UTGTT' },
  18. { productNumber: '03404', productName: 'SCOTTE 5 - UTGTT' },
  19. { productNumber: '03404', productName: 'SCOTTE 20 - UTGTT' },
  20. ......
  21. ]

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:

  1. {
  2. "id":"01",
  3. "categoryName":"Byggmaterial",
  4. "items":[
  5. {
  6. "id":"010",
  7. "categoryName":"Bindemedel och bruk",
  8. "items": [
  9. {
  10. "id":"01001",
  11. "categoryName":"Cement",
  12. "products": [
  13. {
  14. "productNumber":"01001",
  15. "productName":"Tunnfog och Tunnputsbruk A"
  16. },
  17. {
  18. "productNumber":"01001",
  19. "productName":"Tunnfog"
  20. },
  21. .......
  22. ]
  23. }
  24. ]
  25. },

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.

  1. {"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

你可以使用两个相互递归的辅助函数:一个用于选择给定类别的子类别:

  1. function items(cid, level) {
  2. return categories
  3. .filter(c => c.categoryId.startsWith(cid) && c.categoryId.length === level)
  4. .map(process)
  5. }

以及一个用于处理类别的函数:

  1. function process(cat) {
  2. let cid = cat?.categoryId || ''
  3. switch (cid.length) {
  4. case 0:
  5. return {...cat, items: items(cid, 2)}
  6. case 2:
  7. return {...cat, items: items(cid, 3)}
  8. case 3:
  9. return {...cat, items: items(cid, 5)}
  10. case 5:
  11. return {
  12. ...cat,
  13. products: products.filter(p => p.productNumber.startsWith(cid))
  14. }
  15. }
  16. }

最后,只需无参数调用 process()

英文:

You can use two mutually recursive helper functions: one that selects subcategories for the given category:

  1. function items(cid, level) {
  2. return categories
  3. .filter(c => c.categoryId.startsWith(cid) && c.categoryId.length === level)
  4. .map(process)
  5. }

and one that processes a category:

  1. function process(cat) {
  2. let cid = cat?.categoryId || ''
  3. switch (cid.length) {
  4. case 0:
  5. return {...cat, items: items(cid, 2)}
  6. case 2:
  7. return {...cat, items: items(cid, 3)}
  8. case 3:
  9. return {...cat, items: items(cid, 5)}
  10. case 5:
  11. return {
  12. ...cat,
  13. products: products.filter(p => p.productNumber.startsWith(cid))
  14. }
  15. }
  16. }

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: [] });

  1. products.forEach(o =&gt; (catalog[o.productNumber].product ??= []).push(o));
  2. 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:

  1. function hierarchy(categories, products) {
  2. function parent(s) {
  3. while (!map.has(s)) s = s.slice(0, -1);
  4. return map.get(s);
  5. }
  6. const root = { items: [] };
  7. const map = new Map(categories.map(({categoryId: id, ...rest}) => [id, { id, ...rest }])).set("", root);
  8. for (const cat of categories) {
  9. (parent(cat.categoryId.slice(0, -1)).items ??= []).push(map.get(cat.categoryId));
  10. }
  11. for (const prod of products) {
  12. (parent(prod.productNumber).products ??= []).push(prod);
  13. }
  14. return root.items;
  15. }
  16. // Demo
  17. const categories = [
  18. { categoryId: '01', categoryName: 'Building Materials' },
  19. { categoryId: '010', categoryName: 'Binders and Mortars' },
  20. { categoryId: '01001', categoryName: 'Cement' },
  21. { categoryId: '01002', categoryName: 'Mortars' },
  22. { categoryId: '01003', categoryName: 'Lime Products' },
  23. { categoryId: '011', categoryName: 'Building Blocks and Aggregate' },
  24. { categoryId: '01101', categoryName: 'Concrete Blocks' },
  25. { categoryId: '01102', categoryName: 'Brick' },
  26. { categoryId: '02', categoryName: 'Building Materials' },
  27. { categoryId: '020', categoryName: 'Binders and Mortars' },
  28. { categoryId: '02001', categoryName: 'Cement' },
  29. { categoryId: '02002', categoryName: 'Mortars' }
  30. ];
  31. const products = [
  32. { productNumber: '01001', productName: 'Thin Joints and Thin Plaster Mortar A' },
  33. { productNumber: '01001', productName: 'Thin Joints' },
  34. ];
  35. const forest = hierarchy(categories, products);
  36. 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 -->

  1. function hierarchy(categories, products) {
  2. function parent(s) {
  3. while (!map.has(s)) s = s.slice(0, -1);
  4. return map.get(s);
  5. }
  6. const root = { items: [] };
  7. const map = new Map(categories.map(({categoryId: id, ...rest}) =&gt; [id, { id, ...rest }])).set(&quot;&quot;, root);
  8. for (const cat of categories) {
  9. (parent(cat.categoryId.slice(0, -1)).items ??= []).push(map.get(cat.categoryId));
  10. }
  11. for (const prod of products) {
  12. (parent(prod.productNumber).products ??= []).push(prod);
  13. }
  14. return root.items;
  15. }
  16. // Demo
  17. const categories = [
  18. { categoryId: &#39;01&#39;, categoryName: &#39;Byggmaterial&#39; },
  19. { categoryId: &#39;010&#39;, categoryName: &#39;Bindemedel och bruk&#39; },
  20. { categoryId: &#39;01001&#39;, categoryName: &#39;Cement&#39; },
  21. { categoryId: &#39;01002&#39;, categoryName: &#39;Bruksbindemedel&#39; },
  22. { categoryId: &#39;01003&#39;, categoryName: &#39;Kalkvaror&#39; },
  23. { categoryId: &#39;011&#39;, categoryName: &#39;Byggnadsblock och ballast&#39; },
  24. { categoryId: &#39;01101&#39;, categoryName: &#39;Betongblock&#39; },
  25. { categoryId: &#39;01102&#39;, categoryName: &#39;Tegel&#39; },
  26. { categoryId: &#39;02&#39;, categoryName: &#39;Byggmaterial&#39; },
  27. { categoryId: &#39;020&#39;, categoryName: &#39;Bindemedel och bruk&#39; },
  28. { categoryId: &#39;02001&#39;, categoryName: &#39;Cement&#39; },
  29. { categoryId: &#39;02002&#39;, categoryName: &#39;Bruksbindemedel&#39; }
  30. ];
  31. const products = [
  32. { productNumber: &#39;01001&#39;, productName: &#39;Tunnfog och Tunnputsbruk A&#39; },
  33. { productNumber: &#39;01001&#39;, productName: &#39;Tunnfog&#39; },
  34. ];
  35. const forest = hierarchy(categories, products);
  36. console.log(forest);

<!-- end snippet -->

答案4

得分: 0

你可以像这样做:

  1. const getNextPrefixLength = (prefix) =>
  2. // Needed because level 3 has 5 chars
  3. prefix.length + (prefix.length === 3 ? 2 : 1);
  4. const getCategoriesByPrefix = (idPrefix) =>
  5. categories.filter(
  6. ({ categoryId }) =>
  7. categoryId.length === getNextPrefixLength(idPrefix) &&
  8. categoryId.startsWith(idPrefix)
  9. );
  10. const getGroupedCategoryRecursively = ({ categoryId: id, categoryName }) => ({
  11. id,
  12. categoryName,
  13. items: getCategoriesByPrefix(id).map(getGroupedCategoryRecursively),
  14. });
  15. const result = getCategoriesByPrefix("0").map(getGroupedCategoryRecursively);
英文:

You could do it something like this:

  1. const getNextPrefixLength = (prefix) =&gt;
  2. // Needed because level 3 has 5 chars
  3. prefix.length + (prefix.length === 3 ? 2 : 1);
  4. const getCategoriesByPrefix = (idPrefix) =&gt;
  5. categories.filter(
  6. ({ categoryId }) =&gt;
  7. categoryId.length === getNextPrefixLength(idPrefix) &amp;&amp;
  8. categoryId.startsWith(idPrefix)
  9. );
  10. const getGroupedCategoryRecursively = ({ categoryId: id, categoryName }) =&gt; ({
  11. id,
  12. categoryName,
  13. items: getCategoriesByPrefix(id).map(getGroupedCategoryRecursively),
  14. });
  15. const result = getCategoriesByPrefix(&quot;0&quot;).map(getGroupedCategoryRecursively);

huangapple
  • 本文由 发表于 2023年4月6日 20:32:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75949562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定