function updateObjectWithKeyAndValue (object, key, value) {
object = { [key]: value };
let new_object = {[key] : value};
return Object.assign(object, new_object);
}
Error:
Objects updateObjectWithKeyAndValue(object, key, value) returns an object with the original key value pairs and the new key value pair:
Error: Expected { prop2: 2 } to match { prop: 1, prop2: 2 }
If you want your function to update provided object with specific key and value, you just need this:
function updateObjectWithKeyAndValue (object, key, value) {
if (typeof object === 'object' && object !== null) {
object[key] = value;
}
}
Related
I have a nested object as follows, and I want to find out the key name if value is given to me.
const a = {
"key1": 12,
"key2": {
"nkey1": 123,
"nkey2": 345
}
};
const temp = (obj, val) => {
return Object.keys(obj).find(key => !(typeof obj[key] === "object") ? obj[key] === val : temp(obj[key], val))
}
console.log(temp(a, 345));
I wrote the above piece of code. But it gives me output as key2 whereas I want output as nkey2.
What am I doing wrong?
A function returns null if the value is not found, otherwise return the key.
const findKey = (obj, val) => {
if (typeof obj === "object") {
for (const key in obj) {
if (obj[key] === val) {
return key;
} else {
const result = findKey(obj[key], val);
if (result !== null) return result;
}
}
}
return null;
};
const a = {
key1: 12,
key2: {
nkey1: 123,
nkey2: 345,
nkey3: {
dkey1: 232,
dkey2: 777,
},
},
};
const output = findKey(a, 777);
console.log(output);
You can use for-in loop, to iterate over keys. If the value of that key matches val, you can return the key. Else, you can check if value is an object, and use recursion, to check if val matches any value of key in that object.
const a = {
"key1": 12,
"key2": {
"nkey1": 123,
"nkey2": 345
}
};
const temp = (obj, val) => {
for (let i in obj) {
if(obj[i] === val){
return i;
} else if(typeof obj[i] === "object"){
return temp(obj[i], val);
}
}
}
console.log(temp(a, 345));
Take a look at this:
const a = {
"key1": 12,
"key2": {
"nkey1": 123,
"nkey2": 345
}
};
// recursive loop
const find = (obj, search = null) => {
if (typeof obj === "object") {
for (const key in obj) { // loop over each property
if (obj.hasOwnProperty(key) && obj[key] === search) // if obj[key] is the value you are looking for (search)
return key; // return key
else {
let r = find(obj[key], search); // recursive call to find with the new object
if (r !== null) return r; // return key
}
}
}
return null; // default return value is null
}
console.log(12, find(a, 12));
console.log(123, find(a, 123));
console.log(345, find(a, 345));
console.log(0, find(a, 0));
The find() function returns the first value of the the array for which the condition is true.
In the case of key === "key2" the recursive function is called which returns "nkey2" which results in the condition to be true and thats why "key2" is returned.
So again maybe to clear my way of thinking: You expect the find() function to return the result of a function call which is part of a condition. This wont work.
The condition is true on key2 so find returns key2.
Hope this helps you out!
i have an nested object as such:
options = {
religous: {
kosher: {
value: 'Kosher',
chosen: false
},
halal: {
value: 'Halal',
active: false
},
},
vegan: {
value: 'Vegan',
active: false
}
}
It contains nested objects of varying sizes. I would like to get an Array containing the values of any value propery. So for the above object the desired output would be:
['Kosher', 'Halal', 'Vegan']
Order doesn't really matter.
I tried to do so recursively as such:
getListOfLabels = obj => {
const lst = []
for (let key in obj) {
if (obj[key].value) lst.push(obj[key].value)
else return getListOfLabels(obj[key])
}
return lst
}
but I keep getting a RangeError: Maximum call stack size exceeded error.
Any suggestions?
The for...in loop assigns the key. To get the value use obj[key]. If the key is value add to lst, if it's an object, call getListOfLabels on it, and spread the results into lst.push():
const options = {"religous":{"kosher":{"value":"Kosher","chosen":false},"halal":{"value":"Halal","active":false}},"vegan":{"value":"Vegan","active":false}}
const getListOfLabels = obj => {
const lst = []
for (let key in obj) {
const val = obj[key] // get the value
if (key === 'value') lst.push(val) // if the key name is "value" push to lst
else if(typeof val === 'object') lst.push(...getListOfLabels(val)) // if type of value is object, iterate it with getListOfLabels and push the results into lst
}
return lst
}
const result = getListOfLabels(options)
console.log(result)
You could take a recursive approach and check if the object contains a value key.
function getValues(object, key) {
if (key in object) return [object[key]];
return Object.values(object).reduce((r, v) => {
if (v && typeof v === 'object') r.push(...getValues(v, key));
return r;
}, []);
}
var options = { religous: { kosher: { value: 'Kosher', chosen: false }, halal: { value: 'Halal', active: false } }, vegan: { value: 'Vegan', active: false } };
console.log(getValues(options, 'value'));
Here's a succinct approach using reduce :-D
const getValues = options => Object.values(options)
.reduce((acc, optionObj) => (
optionObj.value ? [ ...acc, optionObj.value ] : [
...acc,
...Object.values(optionObj).reduce((arr, { value }) => ([ ...arr, value ]), [])
]), [])
i have this type of object which fetched from Redis
{
'username': 'hamet',
'username_Type': 'string',
'meta': 'object',
'meta_Type': 'object',
'meta.avatar': '/avatar.png',
'meta.avatar_Type': 'string',
'meta.active': 'false',
'meta.active_Type': 'boolean',
'meta.someArr': 'array',
'meta.someArr_Type': 'array',
'meta.someArr.0': 'object',
'meta.someArr.0_Type': 'object',
'meta.someArr.0.field': '123',
'meta.someArr.0.field_Type': 'number',
'meta.someArr.1': 'object',
'meta.someArr.1_Type': 'object',
'meta.someArr.1.field': '321',
'meta.someArr.1.field_Type': 'number'
}
all i want is convert this object to valid object like this:
{
username: 'hamet',
meta: {
avatar: '/avatar.png',
active: false,
someArr: [
{ field: 123 },
{ field: 321 }
]
}
}
once i created iterated function, but there was a problem with that. is it possible to convert with Iterated function and how?
You could create object with value types that you will use for creating new instances of different data types and then use reduce() method to build your object.
const data = {"username":"hamet","username_Type":"string","meta":"object","meta_Type":"object","meta.avatar":"/avatar.png","meta.avatar_Type":"string","meta.active":"false","meta.active_Type":"boolean","meta.someArr":"array","meta.someArr_Type":"array","meta.someArr.0":"object","meta.someArr.0_Type":"object","meta.someArr.0.field":"123","meta.someArr.0.field_Type":"number","meta.someArr.1":"object","meta.someArr.1_Type":"object","meta.someArr.1.field":"321","meta.someArr.1.field_Type":"number"}
const result = {}
const create = {'string': String,'number': Number,'boolean': Boolean,'array': Array,'object': Object}
const findType = (key, obj) => obj[key]
Object.keys(data).forEach(key => {
if (!key.includes('Type')) {
key.split('.').reduce((r, e, i, arr) => {
let type = findType(key + '_Type', data);
let value = create[data[key]] || arr[i + 1] ? new create[type] : new create[type](data[key]).valueOf()
if (data[key] == 'false') value = false
r[e] = r[e] || value;
return r[e]
}, result)
}
})
console.log(result)
Get an array of keys with Object.keys(). Filter out the _Type keys. Sort the keys to ensure that parents (shorter) keys are first, since keys` order in an object is not ensured.
Reduce the array of keys, and for each key get it's value by type. If the type is not object/array use the actual key value. Iterate the result object with Array.forEach(), until you get to the leaf. Add the key with the value.
const obj = {"meta.someArr.1.field":"321","username":"hamet","username_Type":"string","meta":"object","meta_Type":"object","meta.avatar":"/avatar.png","meta.avatar_Type":"string","meta.active":"false","meta.active_Type":"boolean","meta.someArr":"array","meta.someArr_Type":"array","meta.someArr.0":"object","meta.someArr.0_Type":"object","meta.someArr.0.field":"123","meta.someArr.0.field_Type":"number","meta.someArr.1":"object","meta.someArr.1_Type":"object","meta.someArr.1.field_Type":"number"};
const byType = {
object: Object,
array: Array
};
const result = Object.keys(obj)
.filter((k) => !k.includes('_Type')) // remove Type keys
.sort((a, b) => a.length - b.length) // ensures that shorter (parent) keys are first
.reduce((r, k) => {
const type = obj[`${k}_Type`];
const valueByType = byType[type] && byType[type]();
const value = valueByType ? valueByType : obj[k];
const keys = k.split('.');
let current = r;
keys.forEach((key, i) => {
if(!(key in current)) current[key] = value;
else current = current[key];
});
return r;
}, {});
console.log(result);
const result = {};
function apply(obj, value, key, ...keys) {
if(keys.length) {
apply(obj[key] || (obj[key] = {}), value ...keys);
} else {
obj[key] = value;
}
}
for(const [key, value] of Object.entries(yourObj))
apply(result, value, ...key.split("."));
You could use a recursive approach to generate the nested structure. I havent included a check if key is a number so that it creates an array, thats your job ;)
If you prefer functional programming:
const apply = (obj, value, ...keys) => keys.slice(1).reduce((obj, key) => obj[key] || (obj[key] = {}), obj)[keys.pop()] = value;
I'm creating a function and stuck on this prompt:
updateObject() : Should take an object, a key and a value. Should update the property key on object with new value. If does not exist on create it.
This is my code:
function updateObject(object, key, value) {
if (object.key) {
return object.key = value;
} else if (object.key === false) {
return object.key;
}
}
This is the test it's trying to pass:
QUnit.test("updateObject() : Should take an object, a key and a value. Should update the property <key> on <object> with new <value>. If <key> does not exist on <object> create it.", function(assert){
var data = {a: "one", b: "two", "hokey": false};
assert.deepEqual(updateObject(data, "b", "three"), {a:"one", b:"three", hokey: false});
var data = {a: "one", b: "two", "hokey": false};
assert.deepEqual(updateObject(data, "ponies", "yes"), {a:"one", b:"two", hokey: false, ponies: "yes"});
var data = {a: "one", b: "two", "hokey": false};
assert.deepEqual(updateObject(data, "a", Infinity), {a:Infinity, b:"two", hokey: false});
});
What am I doing wrong?
Use square bracket if there is a need to access object key using a variable.Also hasOwnProperty can be used to check if object has a key
function updateObject(object, key, value) {
if (object.hasOwnProperty(key)) {
return object[key] // will return value of the key in that object
} else {
return object[key]=value; // will create a new key and will assign value
}
}
You need to return the updated object from the function for the tests to pass.
function updateObject(object, key, value) {
object[key] = value;
return object;
}
I'm trying to remove properties that are numbers from an object:
function removeNumberValues(obj) {
for (i in obj) {
if (obj['i'] instanceof Number) {
delete obj['i'];
}
}
return obj;
}
But it's not removing numerical properties. Halp? What am I missing?
You need to use the variable i, not the value 'i', and you could check with typeof operator and number as value.
function removeNumberValues(object) {
var key;
for (key in object) {
if (typeof object[key] === 'number') {
delete object[key];
}
}
return object;
}
console.log(removeNumberValues({ a: 'foo', b: 42 }));
With Object.keys and Array#forEach for iterating the keys.
function removeNumberValues(object) {
Object.keys(object).forEach(function (key) {
if (typeof object[key] === 'number') {
delete object[key];
}
});
return object;
}
console.log(removeNumberValues({ a: 'foo', b: 42 }));
Use typeof instead. It's more reliable in this case. Unless the value derives from a Number constructor it's not gonna work.
const obj = {
str: "string",
num: 1,
str2: "string2",
num2: 2
};
console.log(removeNumberValues(obj));
function removeNumberValues(obj) {
Object.keys(obj).forEach(function(key) {
if (typeof obj[key] === 'number') {
delete obj[key];
}
});
return obj;
}