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.


2
  • Do you need to support arbitrary levels of nesting, or only 2? Commented Sep 18, 2018 at 7:13
  • See stackoverflow.com/questions/8051975/… for a general process to access arbitrary levels with a dot notation string like that. Commented Sep 18, 2018 at 7:14

7 Answers 7

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; }

Sign up to request clarification or add additional context in comments.

Comments

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);

3 Comments

This only works for 2 levels deep, not arbitrary prop1.prop2.prop3.prop4... keys.
Sure, but OP didn't specify that such a thing was needed.
@CertainPerformance code should be dynamic for n levels. Will be useful for other users too. I am still happy with your answer.
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);

Comments

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));

Comments

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);

Comments

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;
}

Comments

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.