skip to Main Content

I am trying to split the below array

{
    "Base/Brand/0101-color-brand-primary-red": "#fe414d",
    "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
    "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
    "Base/Brand/0107-color-brand-secondary-black": "#000000",
    "Base/Brand/0103-color-brand-primary-white": "#ffffff",
    "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
    "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
    "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
    "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
    "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b"
}

to something like this

{
  "Base": {
    "Brand": {
      "0101-color-brand-primary-red": "#fe414d",
      "0106-color-brand-secondary-green": "#00e6c3",
      "Light": {
        "Extended": {
          "Red": {
            "0201-color-extended-900-red": "#7f1d1d",
            "0202-color-extended-800-red": "#991b1b"
          }
        }
      }
    }
  }
}

Basically I need to split array by ‘/’ and create nested array
Please help how can I achieve this.

3

Answers


  1. Use Object.entries to get all entries in the original object. Use split('/') to get an array of the object path keys in the output. Then use reduce on that path array to create levels inside the result, until the very last element in the path is reached. At this point, we set the last path element to the required color value.

    const d = {
      "Base/Brand/0101-color-brand-primary-red": "#fe414d",
      "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
      "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
      "Base/Brand/0107-color-brand-secondary-black": "#000000",
      "Base/Brand/0103-color-brand-primary-white": "#ffffff",
      "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
      "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
      "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
      "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
      "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b"
    }
    
    const r = Object.entries(d).reduce((a, [p,v]) => 
      (p.split('/').reduce((a,c,i,r) => 
        a[c] ??= i<(r.length-1) ? {} : v, a), a), {})
    
    console.log(r)
    Login or Signup to reply.
  2. Since the provided structure is a flat (not nested) object of key-value pairs (entries), one could start aggregating the OP’s desired target data-structure by reduceing the source-object’s entries.

    The initial value of this outer reduce task will be an empty object (literal).

    The reducer function of the very same task does receive with each iteration the to be aggregated object reference (which in the very beginning is the initial value / the empty object). It also receives the current iteration’s entry which is a key-value pair provided as an array. The key actually is the key-path, a string which can be further split at every occurring slash. The value is the path-value which has to be assigned as last value of any aggregated (partial) object reference.

    Thus, one is in need of a second, nested, reduce task which does process each of the key-path’ partial key values. The initial value will be always the base or root reference of the to be aggregated object. The inner reduce task does aggregate the received node reference by either accessing an already existing node, or by creating a new (empty node) or by assigning the final path-value to the last created node. It also always does pass this reference as current node into the next iteration step.

    const sampleData = {
      "Base/Brand/0101-color-brand-primary-red": "#fe414d",
      "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
      "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
      "Base/Brand/0107-color-brand-secondary-black": "#000000",
      "Base/Brand/0103-color-brand-primary-white": "#ffffff",
      "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
      "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
      "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
      "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
      "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b",
    };
    
    function createObjectFromKeyPartialsAndValues(data) {
      return Object
        .entries(data)
        .reduce((root, [keyPath, pathValue]) => {
    
          keyPath
            .split('/')
            .reduce((node, key, idx, keyList) => {
    
              const isLastKey = !keyList.hasOwnProperty(idx + 1);
              const value = isLastKey ? pathValue : {};
    
              const obj = (node[key] ??= value);
              return obj;
    
            }, root);
    
          return root;
    
        }, {});
    }
    
    console.log(
      createObjectFromKeyPartialsAndValues(sampleData)
    );
    .as-console-wrapper { min-height: 100%!important; top: 0; }
    Login or Signup to reply.
  3. You can achieve that with a recursive function like the one below :

    const list = {
      "Base/Brand/0101-color-brand-primary-red": "#fe414d",
      "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
      "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
      "Base/Brand/0107-color-brand-secondary-black": "#000000",
      "Base/Brand/0103-color-brand-primary-white": "#ffffff",
      "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
      "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
      "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
      "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
      "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b",
    };
    
    const result = {};
    
    Object.entries(list).forEach((entry) => {
      const path = entry[0]; // "Base/Brand/0101-color-brand-primary-red"
      const value = entry[1]; // "#fe414d"
      sections = path.split("/"); // ["Base", "Brand", "0101-color-brand-primary-red"]
    
      // start creating the output object using a recursive function
      sett(result, sections, sections[0], 0, sections.length, value);
    });
    
    function sett(parentObj, sections, currentSection, currentIndex, depth, value) {
      // stop if we've reached the end of the path
      if (currentIndex >= depth) return;
    
      // if not, check if this is the last section of the path
      const isLastSection = sections[currentIndex + 1] === undefined;
    
      // if there is not already an entry in result for this section (e.g  "Base" or "brand")
      if (!parentObj[currentSection])
        // if it's the end of the path (e.g one of the colors like 0101-color-brand-primary-red) assign it the value else assign {} to it
        parentObj[currentSection] = isLastSection ? value : {};
    
      // else go deeper in the path
      const nextSection = sections[currentIndex + 1];
    
      sett(
        parentObj[currentSection],
        sections,
        nextSection,
        currentIndex + 1,
        depth,
        value
      );
    }
    
    console.log(result);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search