Home > Software engineering >  How to create a nested data structure from 2 arrays?
How to create a nested data structure from 2 arrays?

Time:04-28

Hi guys I get confused trying to qcheave this, so any help would be great!

I have two arrays from which I need a specific object. Source arrays:

1-Types (1D):    ['dev', 'env', 'othr']
2-Services (2D): (3) [Array(3), Array(4), Array(6)]
                 Array(3)
                   0: "1':'Option 11'"
                   1: "2':'Option 12'"
                   2: "3':'Option 13'"

                 Array(4)
                   0: "5':'Option 21'"
                   1: "6':'Option 22'"
                   2: "7':'Option 23'"
                   3: "4':'Option 24'"

                 Array(6)
                   0: "8':'Option 31'"
                   1: "9':'Option 32'"
                   2: "10':'Option 33'"
                   3: "11':'Option 34'"
                   4: "12':'Option 35'"
                   5: "13':'Option 36'"

The desired outcome is this structure:

servData = {
  "dev": {
        "1": "Option 11",
        "2": "Option 12"
        "3": "Option 13"
  },
  "env": {
        "4": "Option 21",
        "5": "Option 22"
        "6": "Option 23",
        "7": "Option 24"
  },
  "othr": {
        "8": "Option 31",
        "9": "Option 32"
        "10": "Option 33",
        "11": "Option 34"
        "12": "Option 35",
        "13": "Option 36"
  }
};

CodePudding user response:

Use this:

const itemNames = ['dev', 'env', 'othr']
const items = [
  [ "1':'Option 11'",
    "2':'Option 12'",
    "3':'Option 13'"
  ], 
  [
    "5':'Option 21'", 
    "6':'Option 22'", 
    "7':'Option 23'", 
    "4':'Option 24'"
  ], 
  [
    "8':'Option 31'", 
    "9':'Option 32'", 
    "10':'Option 33'", 
    "11':'Option 34'", 
    "12':'Option 35'", 
    "13':'Option 36'"
  ]
]
const value = itemNames.map((value, index) => ({ index, value})).reduce((p, el) => {
   p[el.value]={}
   items[el.index].forEach(e=>{
     let [op,...va] =e.split(':');
     va=va.join(':').split('')
     va.splice(0,1)
     va.pop()
     const ar=va.join(':');
     p[el.value][parseInt(op)]=ar;
   })
   return p;
}, {})
console.log(value);

CodePudding user response:

The OP's provided array of stringified entries seems to be mal-formatted ... e.g. "1':'Option 11'", with either a missing or a dispensable single quote for the key part, instead of "'1':'Option 11'" (with single quotes) or "1:'Option 11'" (without single quotes for the key part).

Because of that the beneath presented approach uses a capturing regex like /^'?(?<key>\d )'?:'?(?<value>.*?)'?$/ in order to sanitize (or rather be agnostic to) each provided string based key-value configuration.

The approach itself makes use of Array.prototype.reduce twice.

The outer reduce does process the list of property or item names as propertyName together with a passed entries config which features each property name related array of stringified key-value pairs.

The inner reduce does process such an array, retrieves key and value from the string and, based on this data, assigns a new entry to the value which, within the outer reduce, gets assigned to the newly created propertyName related entry.

function createEntryFromKeyAndEntriesConfig(
  { config = [], result = {} },
  propertyName,
  idx,
) {
  // see ... [https://regex101.com/r/DQbrRM/1]
  const regXKeyValue =
    /^'?(?<key>\d )'?:'?(?<value>.*?)'?$/;

  result[propertyName] = config[idx]
    .reduce((obj, entryString) => {

      const { key = '', value = '' } = regXKeyValue
        .exec(entryString)
        ?.groups;

      obj[key] = value;
      return obj;
    }, {});

  return { config, result };
}

const entriesConfig = [[
  "1':'Option 11'",
  "2':'Option 12'",
  "3':'Option 13'",
], [
  "5':'Option 21'", 
  "6':'Option 22'", 
  "7':'Option 23'", 
  "4':'Option 24'",
], [
  "8':'Option 31'", 
  "9':'Option 32'", 
  "10':'Option 33'", 
  "11':'Option 34'", 
  "12':'Option 35'", 
  "13':'Option 36'",
]];
const propertyNames = ['dev', 'env', 'othr'];

const { result: servData } = propertyNames
  .reduce(createEntryFromKeyAndEntriesConfig, {
    config: entriesConfig,
    result: {},
  });

console.log({ servData });
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

Your data did need some cleanup.

Use Array#map and Array#reduce as follows:

const keys = ['dev', 'env', 'othr'],
      input = [ [ "1:'Option 11'", "2:'Option 12'", "3:'Option 13'" ], [ "5:'Option 21'", "6:'Option 22'", "7:'Option 23'", "4:'Option 24'" ], [ "8:'Option 31'", "9:'Option 32'", "10:'Option 33'", "11:'Option 34'", "12:'Option 35'", "13:'Option 36'" ] ],
      
      output = keys.map(
          (key,i) => 
          ({
              [key]: input[i].reduce(
                  (acc,cur) => 
                  ({...acc,[cur.split(':')[0]]:cur.split(':')[1]}),{})
          })
      );
      
console.log( output );

  • Related