Remove number properties from an object? - javascript

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

Related

Underscore "defaults" from scratch

I've been trying to rewrite the _.defaults method from underscore.js and I keep getting this error:
should copy source properties to undefined properties in the destination object‣
AssertionError: expected { a: 'existing' } to deeply equal { a: 'existing', b: 2, c: 3, d: 4 }
Here's the missing conditions:
-should copy source properties to undefined properties in the destination object and should return the destination object
and my code:
_.defaults = function (destination, source) {
Object.keys(destination).forEach(key => {
if (destination[key] === undefined || destination[key] === null) {
destination[key] = source[key];
}
})
return destination;
};
The idea in _.defaults is that keys from the source object might be missing entirely in the destination object. So you need to iterate the keys of the source object instead of those of the destination object:
_.defaults = function (destination, source) {
Object.keys(source).forEach(key => {
if (destination[key] === undefined || destination[key] === null) {
destination[key] = source[key];
}
})
return destination;
};
Side note: you can write x == null instead of x === null || x === undefined. Saves some precious keystrokes.
_.defaults = function (destination, source) {
Object.keys(source).forEach(key => {
if (destination[key] == null) {
destination[key] = source[key];
}
})
return destination;
};

How to find the key of a nested object by the value in javascript?

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!

How to assign two objects with both having key variables

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

finding undefined or null value from object inside object

i would like to push keys inside array if found undefined or null
const obj = {
name:'ab',
edu:'av',
degres:{
a1:'',
b1:'1'
},
platform:undefined
}
i want an output like
`['a1','platform']`
as the value for a1 and platform were null and undefined
i have treid this solution but it doesnt work
function iterater(obj){
let blankValues = [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object")) {
iterater(obj[key])
} else {
if (typeof obj[key] === "undefined" || obj[key] === ''){
blankValues.push(key);
}
}
})
return blankValues;
}
but this somehow only return ['platform'] only,but the expected output should be ['platform','a1'],i think when running iterater(obj[key]),the value of array (blankValues) gets blank as it doesnt perserve it,but please help me with appropriate logic and structure
The issue is because you're re-defining blankValues as an empty array in every iteration of the recursive loop. To fix this you could accept the array as an optional argument of the function so that values get pushed to it on each iteration.
Also note that, as #ziggy wiggy pointed out in the comments, your logic will fail when a null value is encountered as typeof obj[key] === "object" would be true. You need a specific null check too.
const obj = {
name: 'ab',
edu: 'av',
degres: {
a1: '',
b1: '1'
},
platform: undefined,
foo: null
}
function iterater(obj, arr) {
arr = arr || [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object") && obj[key] !== null) {
iterater(obj[key], arr)
} else {
if (typeof obj[key] === "undefined" || obj[key] === null || obj[key].trim() === '') {
arr.push(key);
}
}
})
return arr;
}
console.log(iterater(obj));
Note that I also added a trim() call to test the empty string. Your previous logic would accept whitespace-filled strings as valid values.
As you said yourself, when you call iterater(obj[key]) it sets a new local blankValues and puts values in it. So i think you should put blankValues outside the function.
And then you don't have to return it (or you can if you want it as a return value).
Or you can pass blankValues as a parameter of iterater in both the main call and the "inside" call
You need to consume the result of recursive call. For example add it back to blankValues like this blankValues.push(...iterater(obj[key]))
const obj = {
name:'ab',
edu:'av',
degres:{
a1:'',
b1:'1'
},
platform:undefined
}
function iterater(obj){
let blankValues = [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object")) {
blankValues.push(...iterater(obj[key]))
} else {
if (typeof obj[key] === "undefined" || obj[key] === ''){
blankValues.push(key);
}
}
})
return blankValues;
}
console.log(iterater(obj))
You must push the result returned by the recursive call to your array.
Change:
iterater(obj[key])
for:
blankValues.push(...iterater(obj[key]))
const obj = {
name: 'ab',
edu: 'av',
degres: {
a1: '',
b1: '1'
},
platform: undefined
}
function iterater(obj){
let blankValues = [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object")) {
blankValues.push(...iterater(obj[key]))
} else {
if (typeof obj[key] === "undefined" || obj[key] === ''){
blankValues.push(key);
}
}
})
return blankValues;
}
console.log(iterater(obj));
Here is another way to do it using Object.entries(), Object.keys(), Array.reduce(), Array.flat() and Array.isArray(). This implementation works for arrays too.
const obj = {
name:'ab',
edu:'av',
something: [{ a: 1 }, { a: '' }],
degres:{
a1:'',
b1:'1'
},
platform:undefined
};
function getEmptyProps(obj) {
if (!Object.keys(obj).length) { return []; }
return Object.entries(obj).reduce((acc, [key, val]) => {
if (val === undefined || val === null || val.toString().trim() === '') {
acc.push(key);
} else if (Array.isArray(val)) {
acc.push(val.map(getEmptyProps).flat());
} else if (typeof val === 'object') {
acc.push(getEmptyProps(val));
}
return acc.flat();
}, []);
}
console.log(getEmptyProps(obj))
You could take a check for falsy keys and return the key, if the property is an object, the check the object.
const
getFalsy = o => Object.keys(o).reduce((r, k) => {
if (!o[k]) return [...r, k];
if (typeof o[k] === 'object') return [...r, ...getFalsy(o[k])];
return r;
}, []),
object = { name: 'ab', edu: 'av', degres: { a1: '', b1: '1' }, platform: undefined };
console.log(getFalsy(object));

Is there any simple and clear way to search values in arbitrary deep branchy objects?

I see one smart way: using JSON.stringify to recursively traverse objects like this:
function search(obj, str) {
let flag = false;
JSON.stringify(obj, (key, value) => {
if (typeof value === "object") return value;
else {
// doesn't take into account Date cases etc
if (value.indexOf(str) >= 0) {
flag = true;
}
}
})
return flag;
}
P.S: Not sure about tags.
You could use a traditional iterative and recursive approach by using a depth-first search.
function findString(object, string) {
return Object.keys(object).some(k => typeof object[k] === 'object'
? findString(object[k], string)
: object[k].includes(string)
);
}
var object = { a: 'aaa', b: 'bbb', c: { d: 'ddd', e: { f: 'fff', g: 'ggg' } } };
console.log(findString(object, 'ggg'));
console.log(findString(object, 'foo'));

Categories