2

I have the following code:

const temp = {
  "address.addr1": "Some value 1",
  "address.addr2": "Some value 2",
  "qual.qual1": "Some value 1",
  "qual.qual2": "Some value 2",
  "gender": "Male"
}

let finalVal = {};

transformValues(temp);

function splitKeys(value) {
  const splitValues = value.split('.');
  console.log(splitValues)

}

function transformValues(values) {

  const keys = Object.keys(values);
  keys.forEach(key => {
    splitKeys(key);
  });
}

I would like the output to have the following format:

let finalVal = {
    address: {
    addr1: "Some value 1",
    addr2: "Some value 2"
  },
  qual: {
    qual1: "Some value 1",
    qual2: "Some value 2"
  },
  gender: "Male"
}

Please help me to use JavaScript to console the output like above. I have tried using lodash, split and slice, but I couldn't crack that output.


ponury-kostek
  • 7,824
  • 4
  • 23
  • 31
Kaaviya N
  • 23
  • 2
  • Do you need to support arbitrary levels of nesting, or only 2? – Barmar Sep 18 '18 at 07:13
  • See https://stackoverflow.com/questions/8051975/access-object-child-properties-using-a-dot-notation-string for a general process to access arbitrary levels with a dot notation string like that. – Barmar Sep 18 '18 at 07:14

7 Answers7

3

You could use a function for spliting the path to the value and generate new objects for it.

It works for any depth.

function setValue(object, path, value) {
    var last = path.pop();
    path.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
    return object;
}

var temp = { "the.ultimate.question": 42, "address.addr1": "Some value 1", "address.addr2": "Some value 2", "qual.qual1": "Some value 1", "qual.qual2": "Some value 2", "gender": "Male" },
    finalVal = {};

Object
    .entries(temp)
    .forEach(([k, v]) => setValue(finalVal, k.split('.'), v));

console.log(finalVal);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

You can use reduce over the entries of the input, checking whether the key has a period or not. If so, assign to the appropriate nested key in the accumulator, creating the outer object first, if needed.

const temp = {
 "address.addr1": "Some value 1",
  "address.addr2": "Some value 2",
  "qual.qual1": "Some value 1",
  "qual.qual2": "Some value 2",
  "gender": "Male"
}
const finalVal = Object.entries(temp).reduce((a, [key, val]) => {
  if (!key.includes('.')) {
    a[key] = val;
    return a;
  }
  const [outerProp, innerProp] = key.split('.');
  if (!a[outerProp]) a[outerProp] = {};
  a[outerProp][innerProp] = val;
  return a;
}, {});
console.log(finalVal);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

Another solution that works for any level would be:

var temp = {
  "address.addr1": "Some value 1",
  "address.addr2": "Some value 2",
  "qual.qual1": "Some value 1",
  "qual.qual2": "Some value 2",
  "gender": "Male"
};

var res = Object.entries(temp).reduce((m, [keys, value]) => {
    var curr = m;
    keys.split('.').forEach((key, i, self) => curr = curr[key] = i === self.length - 1 ? value : curr[key] || {});
    return m;
}, {});

console.log(res);
Faly
  • 13,291
  • 2
  • 19
  • 37
0

You can use Array.reduce and Object.entries

const temp = {"address.addr1": "Some value 1","address.addr2": "Some value 2","qual.qual1": "Some value 1","qual.qual2": "Some value 2","gender": "Male"};

// For each key/value pair in object populate the resultant object
const result = Object.entries(temp).reduce((a,[k,v]) => {
  populateObject(a, k, v);
  return a;
}, {});

// function that traverses the hierarchy in object and add the value
function populateObject(obj, k, v) {
  if(k.includes(".")) {
    let keys = k.split(".");
    let key = keys.shift();
    obj[key] = obj[key] || {};
    populateObject(obj[key], keys.join("."), v);
  } else obj[k] = v;
}
console.log(result);
Nikhil Aggarwal
  • 28,197
  • 4
  • 43
  • 59
0

const temp = {
    "address.addr1": "Some value 1",
    "address.addr2": "Some value 2",
    "qual.qual1": "Some value 1",
    "qual.qual2": "Some value 2",
    "gender": "Male"
}
  
let finalVal = transformValues(temp);
console.log(finalVal);

function transformValues(values) {
    const result = {};
    Object.keys(values).forEach(key => {
        let temp = result;
        const splits = key.split('.');
        for (let i = 0; i < splits.length - 1; i++) {
            temp = temp[splits[i]] = temp[splits[i]] || {};
        }
        temp[splits.pop()] = values[key];
    });
    return result;
}
AvcS
  • 2,263
  • 11
  • 18
0

Try this code

const temp = {
    "address.addr1": "Some value 1",
    "address.addr2": "Some value 2",
    "qual.qual1": "Some value 1",
    "qual.qual2": "Some value 2",
    "gender": "Male"
};

let finalVal = {};

Object.keys(temp).forEach((key) => {
    const array = key.split('.');
    if(array.length > 1){
        if(finalVal[array[0]])
            finalVal[array[0]][array[1]] = temp[key];
        else
            finalVal[array[0]] = { [array[1]] : temp[key] }
    }
    else {
        finalVal[array[0]] =  temp[key];
    }
});
console.log(finalVal)
fahad
  • 129
  • 1
  • 1
  • 10
0

Don't forget to return your values from function. Otherwise it will return undefined. I think you should study scope and functions.

https://developer.mozilla.org/cs/docs/Web/JavaScript/Reference/Functions

And here is a alternative solution for your problem.

const temp = {
  "address.addr1": "Some value 1",
  "address.addr2": "Some value 2",
  "qual.qual1": "Some value 1",
  "qual.qual2": "Some value 2",
  "gender": "Male"
}    

function splitKeys(value) {
  const splitValues = value.split('.');

  // return splited values as an array
  return splitValues;
}

function transformValues(values) {
  // create new object
  let obj = {};

  const keys = Object.keys(values);
  keys.forEach(key => {
    const [rootKey, branchKey] = splitKeys(key);
    // assign empty object if obj[rootKey] is empty
    if(obj[rootKey] === undefined) { obj[rootKey] = {}; }
    // this will format the obj as you wanted
    if(branchKey === undefined){
      obj[rootKey] = values[key]; 
    } else {
      obj[rootKey][branchKey] = values[key]; 
    }
  });

  return obj;
}

console.log(temp);
console.log(transformValues(temp));
Yusuf Yalim
  • 118
  • 6