-2

I am looking for a way to deep merge the following data structure into a unique array of objects in Javascript.

I have explored lodash, reducers, etc and can only get as far as uniquely merging the first nested level.

Starting from this format:

[
  "/Apparel",
  "/Apparel/Jewelry",
  "/Apparel/Jewelry/Rings",
  "/Apparel/Jewelry/Precious & Semi-Precious Gems & Gemstone Jewelry",
  "/Apparel/Jewelry/Rings/Engagement Rings",
  "/Apparel/Jewelry/Precious & Semi-Precious Gems & Gemstone Jewelry/Diamond Jewelry"
]

I have arrived at the following data structure:

[
  {
    "Occasions & Gifts": {}
  },
  {
    "Apparel": {}
  },
  {
    "Apparel": {
      "Clothing": {}
    }
  },
  {
    "Occasions & Gifts": {
      "Special Occasions": {
        "Weddings": {}
      }
    }
  },
  {
    "Apparel": {
      "Clothing": {
        "Women's Clothing": {
          "Dresses": {}
        }
      }
    }
  },
  {
    "Apparel": {
      "Clothing": {
        "Formal Wear": {}
      }
    }
  },
  {
    "Apparel": {
      "Clothing": {
        "Formal Wear": {
          "Bridal Wear": {}
        }
      }
    }
  },
  {
    "Occasions & Gifts": {
      "Special Occasions": {}
    }
  },
  {
    "Apparel": {
      "Clothing": {
        "Women's Clothing": {}
      }
    }
  }
]

By deep merging these uniquely I should have a data structure I can work with and iterate through to display on front-end.

The ideal output for the above would be:

  {
    "Occasions & Gifts": {
      "Special Occasions": {
        "Weddings": {}
      }
    }
  },
  {
    "Apparel": {
      "Clothing": {
        "Women's Clothing": {
           "Dresses": {}
        }
        "Formal Wear": {
           "Bridal Wear": {}
        }
      }
    }
  }
]

or even better something like:

[
  {
    "title": "Apparel",
    "subTerms": [
      {
        "title": "Jewellery",
        "subTerms": [
          {
            "title": "Rings",
            "subTerms": [
              {
                "title": "Engagement Rings",
                "subTerms": []
              }
            ]
          }
        ]
      },
      {
        "title": "Precious & Semi-Precious Gems & Gemstone Jewelry",
        "subTerms": [
          {
            "title": "Diamond Jewelry",
            "subTerms": []
          }
        ]
      }
    ]
  }
]

Link to pen

Sjmc11
  • 31
  • 7
  • It is not clear which logic brings you from the first array to the end result. For example: The original array has no "Weddings", yet it suddenly appears. Please give a consistent example of input - expected output, and *explain* what the logic is. – trincot Dec 16 '21 at 13:41
  • _"Link to pen"_ -> [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) + [mcve] – Andreas Dec 16 '21 at 13:41
  • The title has nothing to do with the _"even better"_ expected output. You have an array of paths and you want to convert them into an object. – Andreas Dec 16 '21 at 13:43
  • [How to set object property (of object property of..) given its string name in JavaScript?](https://stackoverflow.com/questions/13719593/how-to-set-object-property-of-object-property-of-given-its-string-name-in-ja) + a loop – Andreas Dec 16 '21 at 13:44

1 Answers1

0

To get the one with a bunch of objects, it is just a couple of reduce functions

const links = [
  "/Apparel",
  "/Apparel/Jewelry",
  "/Apparel/Jewelry/Rings",
  "/Apparel/Jewelry/Precious & Semi-Precious Gems & Gemstone Jewelry",
  "/Apparel/Jewelry/Rings/Engagement Rings",
  "/Apparel/Jewelry/Precious & Semi-Precious Gems & Gemstone Jewelry/Diamond Jewelry"
];

const data = links.reduce((obj, link) => {
  const parts = link.split("/");
  parts.reduce((obj, part) => {
    if (!part) return obj;
    obj[part] =  obj[part] || {};
    return obj[part];
  }, obj);
  return obj;
}, {});

console.log(data);

To get the subterms way, it is a bit more complicated. You need to keep a reference to objects and you need to push that reference to arrays.

const links = [
  "/Apparel",
  "/Apparel/Jewelry",
  "/Apparel/Jewelry/Rings",
  "/Apparel/Jewelry/Precious & Semi-Precious Gems & Gemstone Jewelry",
  "/Apparel/Jewelry/Rings/Engagement Rings",
  "/Apparel/Jewelry/Precious & Semi-Precious Gems & Gemstone Jewelry/Diamond Jewelry"
];

const data = links.reduce(({ items = [], lookup = {} }, link) => {
  const parts = link.split("/");
  parts.reduce(({ path, lookup }, title) => {
    if (!title) return { path, lookup };
    const parentKey = path.join("/");
    path.push(title);
    const key = path.join("/");
    if (!lookup[key]) {
      lookup[key] = { title, subTerms: [] };
      if (parentKey) {
        lookup[parentKey].subTerms.push(lookup[key]);
      } else {
        items.push(lookup[key]);
      }
    }
    return { path, lookup };
  }, { items, path: [], lookup });
  return { items, lookup };
}, {} ).items;

console.log(data);
epascarello
  • 195,511
  • 20
  • 184
  • 225