1

I have an array. Let's say it's:

const array = ["lvl1", "lvl2", "lvl3", "key"]

I have a value. Let's say it's:

const value = false

I have an object. Let's say it's:

const object = {
  lvl1: {
    dogs: "bark",
    lvl2: {
      cats: "meow",
      lvl3: {
        cows: "moo"
        key: true
      }
    }
  }
}

How do I create a function that takes in the array and value, then updates the object so that the key in the array (the last item in the array) is updated with the new value? It needs to be nested appropriately based on the first array.length - 1 strings in the array.

For example, let's called the function createObject. If I call it using the array and value already defined above as:

const newObject = createObject(array, value)

Then newObject should be equal to:

{
  lvl1: {
    dogs: "bark",
    lvl2: {
      cats: "meow",
      lvl3: {
        cows: "moo"
        key: false
      }
    }
  }
}

Here's another example with a different level of nesting:

const updatedObject = createObject(["lvl1", "lvl2", "cats"], "stink")

Then updatedObject should be equal to:

{
  lvl1: {
    dogs: "bark",
    lvl2: {
      cats: "stink",
      lvl3: {
        cows: "moo"
        key: true
      }
    }
  }
}

I've gotten this far but it's not working:

import object from "./object"

const createObject = (array, value) => {
  let results = object;
  for (let i = 0; i < array.length; i++) {
    i === array.length - 1
      ? (results = results[array[i]] = {
          ...results[array[i]],
          [array[i]]: value
        })
      : (results = results[array[i]] = {
          ...results[array[i]],
          [results[array[i]]]: {}
        });
    }
  return results;
}

I don't want to change the initial object. I want to return a new object. And I won't be adding any new key/value pairs to the object, only changing existing key/value pairs.

2
  • do you want to get a new independent object? Commented May 2, 2019 at 15:19
  • Yes, I don't want to change the existing object. The existing object is actually the state in my React app so I don't want to change it directly. Commented May 2, 2019 at 15:21

2 Answers 2

2

This is a bit more generic because it doesn't assume the source is a global variable named object:

let array = ["lvl1", "lvl2", "lvl3", "key"];
let value = false;

let createObject = (keys, value) => {
  let o, obj = o = {};
  let lastKey = keys.pop();
  keys.forEach(key => o = o[key] = o[key] || {});
  o[lastKey] = value;
  return obj;
};

let addToObject = (obj, keys, value) => {
  let o, copy = o = JSON.parse(JSON.stringify(obj));
  let lastKey = keys.pop();
  keys.forEach(key => o = o[key] = o[key] || {});
  o[lastKey] = value;
  return copy;
};

let x = createObject(array, value);
let y = addToObject(x, ['lvl1'], 3);
let z = addToObject(y, ['a', 'b', 'c'], 4);

console.log(x);
console.log(y);
console.log(z);

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

4 Comments

Running both the snippet above and your codepen snippet, I see the expected results (same as in your comment).
You're right, the codepen snipped was cutting off the console in the in-browser console. If I check the console on Chrome it's there. Thanks! I'll mark this as the correct answer and will update my post with the final code I used to get my exact requirements.
Although one issue I noticed is that o is undefined in addToObject.
I don't get that error in chrome, but you're right, let a = b = 0 declares a but not b. Updated my answer to explicitly declare o.
0

You could take the entries and build new object and check if the actual key is equal to the first item of the array, then check the length of the rest array as well and take the value. For a nested copy take a check for an object and build a new deeper level by calling the function again.

function getObject(object, [key, ...keys], value) {
    return Object.assign({}, ...Object
        .entries(object)
        .map(([k, v ]) => ({ [k]: k === key && !keys.length
            ? value
            : v && typeof v === 'object'
                ? getObject(v, k === key ? keys : [], value)
                : v
        })),
        Object.keys(object).includes(key) || { [key]: keys.length
            ? getObject({}, keys, value)
            : value
        }
    );
}

const
    object1 = { lvl1: { dogs: "bark", lvl2: { cats: "meow", lvl3: { cows: "moo", key: true } } } },
    object2 = getObject(object1, ["lvl1", "lvl2", "lvl3", "key"], false),
    object3 = getObject(object2, ["lvl1", "lvl2", "cats"], "stink"),
    object4 = getObject({}, ["lvl1", "lvl2", "cats"], "stink");;

console.log(object1);
console.log(object2);
console.log(object3);
console.log(object4);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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.