Recursively check object field (+ nested) to be true - javascript

I have that object :
obj = {
a: true,
b: {
c: false,
d: true
}
What's the best way to check if all fields of my object is set to true. In case all fields are true => result should be true, if not => false.

This solution recursively checks if all the values are truthy.
const obj = {
a: true,
b: {
c: false,
d: true
}
}
const checkRecursive = (obj) => {
return Object.values(obj).every(el => typeof el === "object" ? checkRecursive(el) : el);
}
console.log(checkRecursive(obj));

Try this.
let obj = {
a: true,
b: {
c: false,
d: true
}
};
let objArray = []
function validate(obj) {
for(const item in obj) {
if(typeof obj[item] === 'object') {
validate(obj[item]);
} else {
objArray.push(obj[item]);
}
}
}
validate(obj);
// Use filter to check if there are any false value.
console.log(objArray.filter( item => !item).length === 0);

You can create your own recursive function with logic similar to the example below:
const obj = {
a: true,
b: {
c: {
d: true,
e: {
f: false
}
},
g: false,
h: {
i: false,
j: true,
k: {
l: false
}
}
},
m: {
n: true,
o: false,
p: {
q: {
r: {
s: {
t: true,
u: {
v: false,
w: true
}
}
}
}
}
}
}
function deepSearchForValue(o, searchValue) {
let found = false;
const level = [];
const keys = [];
function deepSearch(o) {
for (let [prop, value] of Object.entries(o)) {
if (value === searchValue) {
found = true;
keys.push(`${level.join('.')}.${prop}`);
} else if (typeof value === 'object') {
level.push(prop);
deepSearch(value);
level.pop();
}
}
}
deepSearch(o);
return [found, keys];
}
const [hasFalseValues, falseValueKeys] = deepSearchForValue(obj, false);
if (hasFalseValues) {
falseValueKeys.forEach(s => console.info(`false found at ${s}`));
}

Related

remove nested null or empty values from object [duplicate]

I got an object which looks like this :
{
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0,
"k": null
},
"l": {
"m": null
},
"n": {
"o": 1,
"p": "string (not empty)",
"q": {}
},
"r": [],
"l": "2000-01-01T01:01:00.000Z",
}
Thanks to the code provided by here : https://stackoverflow.com/a/38364486/3912805 I can now remove all null values of my nested object.
I used this function so far to removeNull :
removeNull = (obj) => {
Object.keys(obj).forEach(key =>
(obj[key] && typeof obj[key] === 'object') && removeNull(obj[key]) ||
(obj[key] === undefined || obj[key] === null) && delete obj[key]
);
return obj;
};
But I would like to enhance this function to allow me to remove all empty arrays or any empty collection which may exists in my nested object.
Final results should be without k, l & m, q, r, l:
{
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0
},
"n": {
"o": 1,
"p": "string (not empty)"
},
"l": "2000-01-01T01:01:00.000Z",
}
I need to keep all values which were set to 0 or to false.
I would like to enhance this removeNull's method using ES6 method, but so far I failed to do it.
I also tried old school method which was used for this How to deeply remove null values, empty objects and empty array from an object
itemToBool = item => {
if (typeof item !== 'object' || item === null) return item;
const cleanedItem = cleanObject(item);
return Object.keys(cleanedItem).length !== 0 && cleanedItem;
};
cleanObject = obj => {
if (Array.isArray(obj)) {
const newArr = obj.map(itemToBool).filter(Boolean);
return newArr.length && newArr;
}
const newObj = Object.entries(obj).reduce((a, [key, val]) => {
const newVal = itemToBool(val);
if (newVal !== null || newVal === false) a[key] = newVal;
return a;
}, {});
return Object.keys(newObj).length > 0 && newObj;
};
but it fails too.
You could take an straight forward approach by iterating the key/value pairs of the object and iterate nested iterable objects first and then delete the unwanted keys.
function clean(object) {
Object
.entries(object)
.forEach(([k, v]) => {
if (v && typeof v === 'object') {
clean(v);
}
if (v && typeof v === 'object' && !Object.keys(v).length || v === null || v === undefined) {
if (Array.isArray(object)) {
object.splice(k, 1);
} else {
delete object[k];
}
}
});
return object;
}
var object = { a: "string not empty", b: { c: "string not empty" }, d: { e: false, f: 0, g: true, h: 10 }, i: { j: 0, k: null }, l: { m: null }, n: { o: 1, p: "string (not empty)", q: {} }, r: [{ foo: null }] };
console.log(clean(object));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can exploit JSON.stringify and it's optional second argument replacer but be aware the following code removes null and undefined.
const sanitize = (obj) => {
return JSON.parse(JSON.stringify(obj, (key, value) => {
return (value === null ? undefined : value);
}));
};
const obj = {
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0,
"k": null
},
"l": {
"m": null
},
"n": {
"o": 1,
"p": "string (not empty)",
"q": {}
},
"r": [],
"l": "2000-01-01T01:01:00.000Z",
}
console.log(sanitize(obj))
Thanks to Nina Scholz, my enhanced version will be :
cleanObject = function(object) {
Object
.entries(object)
.forEach(([k, v]) => {
if (v && typeof v === 'object')
cleanObject(v);
if (v &&
typeof v === 'object' &&
!Object.keys(v).length ||
v === null ||
v === undefined ||
v.length === 0
) {
if (Array.isArray(object))
object.splice(k, 1);
else if (!(v instanceof Date))
delete object[k];
}
});
return object;
}
If you don't want to mutate the object and need a new copy, then you can stringify the object to json and parse it, and filter at the time of parsing. If you don't need the source object then you can override the result into same reference. Its may not the performance efficient approach but obviously much cleaner and not a self recursive approach.
var obj = {
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0,
"k": null
},
"l": {
"m": null
},
"n": {
"o": 1,
"p": "string (not empty)",
"q": {}
},
"r": [],
"s": {"t": null},
"u": [null, {"v": {}}]
}
function copyNonEmpty(o) {
let ignores = [null, undefined, ""],
isNonEmpty = d => !ignores.includes(d) && (typeof(d) !== "object" || Object.keys(d).length)
return JSON.parse(JSON.stringify(o), function(k, v) {
if (isNonEmpty(v))
return v;
});
}
var res = copyNonEmpty(obj);
console.log(JSON.stringify(res, null, 4));
If value is Object or Array then typeof will return object and Object.keys will return a array of keys for both the cases ("0", "1",2... in case of array), and the array length (of keys) will 0 if its an empty array or object. So, conditionally, it will must not (null, undefined or "") and (either a non object/array OR object/array which is non-empty and then you can take that value.
To remove empty arrays, strings, null, undefined values
function removeEmptyElements(obj) {
if (Array.isArray(obj)) {
obj.forEach((element, index) => obj.splice(index, 1, removeEmptyElements(element)));
return obj;
}
return Object.fromEntries(Object.entries(obj)
.filter(([, v]) => (Array.isArray(v) ? v.length !== 0 : (v !== null && v !== '' && v !== undefined)))
.map(([k, v]) => [k, v === (Object(v)) ? removeEmptyElements(v) : v]));
}
have just solved the same issue, so I want to share with you guys. My code also clean nested object and array, can be customize depend on your requirement :
cleanObject = (input) => {
if (typeof input === 'object' && input !== null) {
if(Array.isArray(input)) {
return input.map(cleanObject)
.filter(item => item !== null && item !== undefined)
}
return Object.fromEntries(
Object.entries(input)
.map(([key, val]) => [key, cleanObject(val)])
.filter(([k, v]) => v !== null && v !== undefined)
);
}
return input;
}
// testcase:
const testVal = {
a: 1,
b: 2,
c: undefined,
d: { a: 99, b: null },
e: { a: 1, b: 2, d: undefined, g: null, e: 0 },
f: [1, 0, null, undefined],
g: [1, 2],
h: { aa: 1, bb: { c: 1, d: [111, null], e: 'hello' } },
};
cleanObject(testVal);
you can try this
var testvar = {
test1: null,
test2: 'string',
test3: 3,
}
function removenull(obj) {
for (var propName in obj) {
if (obj[propName] === null || obj[propName] === undefined) {
delete obj[propName];
}
}
return obj
}
console.log(testvar);
console.log(removenull(testvar));
I tried it by as follow
const test = {
a: '',
b: 1,
c: [],
d: {
e: null,
f: 0,
g: undefined,
h: {
i: 'test',
j: {},
k: '',
l: {
m: 'yo test',
n: 'go for it'
}
}
},
e: 'yo tested'
};
const JS_PRIMITIVE_TYPES = { 'string': 1, 'number': 1, 'undefined': 1, 'boolean': 1,
'symbol': 1 }
const isValuePrimitiveType = (value) => {
const typeOfVal = typeof value;
if (JS_PRIMITIVE_TYPES.hasOwnProperty(typeOfVal)) {
return true;
}
return false;
}
/* MAIN Function which runs and call other functions
allKeys : keys of object Object.keys(test);
badJson : json which needs to be update
*/
const iterateObjForRemoveEmptyElem = (badJson, allKeys) => {
for (let index = 0; index < allKeys.length; index++) {
const key = allKeys[index];
if (isEmpty(badJson[key])) {
delete badJson[key];
} else if (Array.isArray(badJson[key]) || isValuePrimitiveType(badJson[key])) {
continue;
}
else {
const newKeys = Object.keys(badJson[key]);
const newJson = Object.assign({}, badJson[key]);
badJson[key] = iterateObjForRemoveEmptyElem(newJson, newKeys);
}
}
return badJson;
}
const isEmpty = (val) => {
if(val === '' || val === null || val === undefined ) {
return true;
} else if (Array.isArray(val) && val.length === 0){
return true;
} else if(typeof val === 'object' && Object.keys(val).length === 0){
return true;
}
return false;
}
const myKeys = Object.keys(test);
console.log("Final Result:::::",JSON.stringify(iterateObjForRemoveEmptyElem(test,myKeys)));
This works for me upto nth level
function cleanObject(obj: object) {
// remove all keys with undefined values in nested objects
const cleaned = Object.entries(obj).reduce((acc, [key, val]) => {
if (val && typeof val === 'object') {
val = cleanObject(val);
}
if (val !== undefined) {
acc[key] = val;
}
return acc;
}, {});
return cleaned;
}
const data = {
a: 50,
b: 90,
c: undefined,
d: undefined,
e: {
a: 90,
b: 80,
c: undefined,
d: undefined,
},
f: {
a: undefined,
b: undefined,
c: undefined,
d: undefined,
},
};
console.log(cleanObject(data));
output => { a: 50, b: 90, e: { a: 90, b: 80 }, f: {} }
// remove all falsy attributes for all layers of object
const removeFalsyProps = (body) => {
let data = body;
Object.keys(data).forEach((key) => {
let value = data[key];
// trim string type value
if (typeof value == 'string') {
value = value.trim();
}
// check value is falsy or not, then delete the property
if (!value) {
delete data[key];
}
// check value is object or not, If object then recursively call. (In JS null and array is object type)
if (typeof value == 'object' && value != null && !Array.isArray(value)) {
removeFalsyProps(value);
}
});
return data;
};
const myOb = {
a: 2,
y: undefined,
x: 0,
s: null,
b: ' ',
c: { d: 8, i: '', j: { k: 1, l: '', m: { o: null, p: 'seven' } } },
e: 'test',
h: { a: '', b: 8, c: { d: 'de', e: 0 } },
i: { array: ['hello'], bc: '' },
j: 45,
array: [],
};
console.log(removeFalsyProps(myOb));
//sample Json Response
var items = {
name: 'test',
randomArray: [],
randomObject: {
id: null,
someObject: {},
someInternalArray: [],
someUndefinedObject: undefined,
},
New name: null,
nestedObject: [
{
emp: {
id: null,
},
empAssets: 2,
joiningDate: {
startDate: null,
endDate: '2019/12/01',
Addresses: [],
},
},
],
};
this.removeEmptyKeys(items);
console.log('the final items ‘,items);
//Removing logic
removeEmptyKeys(yourObject) {
Object.keys(yourObject).forEach(key => {
if (
Object.prototype.toString.call(yourObject[key]) === '[object Date]' &&
(yourObject[key].toString().length === 0 ||
yourObject[key].toString() === 'Invalid Date')
) {
delete yourObject[key];
} else if (yourObject[key] && typeof yourObject[key] === 'object') {
this.removeEmptyKeysFromObject(yourObject[key]);
} else if (yourObject[key] == null || yourObject[key] === '') {
delete yourObject[key];
}
if (
yourObject[key] &&
typeof yourObject[key] === 'object' &&
Object.keys(yourObject[key]).length === 0 &&
Object.prototype.toString.call(yourObject[key]) !== '[object Date]'
) {
delete yourObject[key];
}
});
return yourObject;
}
Remove undefined, null, empty string , empty Arrays. Upvote if it helps.

Can we do addition of two or more objects of same type?

I have 3 objects of the same type with different values of their property. I would like to add them together as follow :
For example
objA = {
data: {
SH: { propertyA: 0, propertyB: 3, propertyC: 0},
....
}
}
objB = {
data: {
SH: { propertyA: 0, propertyB: 0, propertyC: 1},
....
}
}
objC = {
data: {
SH: { propertyA: 4, propertyB: 0, propertyC: 0},
....
}
}
And what I want a result like
objC = {
data: {
SH: { propertyA: 4, propertyB: 3, propertyC: 1},
...
}
}
is it possible to add them?
And if not, do you suggest any efficient way of coding for this instead of having three different types for each of them?
EDIT: By addition, I mean numerical addition of property values from the three objects. Though the objects also have some properties which could be string, I am only interested in number values.
In the end it is a lot of looping. How you do the looping can be done a bunch of ways. Easiest way os to look over the objects themselves and add things when they do not exist.
objA = {
data: {
SH: { propertyA: 0, propertyB: 3, propertyC: 0, x: 'funky-chicken'},
OP: { OO: 1, ZZ: 2 },
}
}
objB = {
data: {
SH: { propertyA: 0, propertyB: 0, propertyC: 1, x: 'funky-chicken'},
OP: { OO: 1, YY: 100 },
}
}
objC = {
data: {
SH: { propertyA: 4, propertyB: 0, propertyC: 0},
AA: { A: 1 },
}
}
const result = [objA, objB, objC].reduce(({ data }, obj) => {
const entries = Object.entries(obj.data);
entries.forEach(([key, items]) => {
if (!data[key]){
data[key] = { ...items };
} else {
Object.entries(items).forEach(([item, value]) => {
if(typeof value === 'number') {
data[key][item] = ( data[key][item] || 0 ) + value;
}
});
}
});
return { data };
}, { data: {} })
console.log(result);
As an alternative, here's one that sums any numbers at any level
The non-number values will have the value of the last object processed (this can be changed if required)
This doesn't handle array properties properly
const objA = {
data: {
num: 1,
SH: {
propertyA: 0,
propertyB: 3,
propertyC: 0
},
text: 'objA',
x: {
y: {
a: 1,
b: 2,
c: 3
}
}
}
};
const objB = {
data: {
num: 2,
SH: {
propertyA: 0,
propertyB: 0,
propertyC: 1
},
text: 'objB',
x: {
y: {
b: 4
}
}
}
};
const objC = {
data: {
SH: {
propertyA: 4,
propertyB: 0,
propertyC: 0
},
text: 'hello world',
x: {
y: {
a: 1
}
}
}
};
const addObjects = (...objs) => objs.reduce((result, obj) => {
const fn = (obj, dest = result) => {
Object.entries(obj).forEach(([key, value]) => {
if (typeof value === 'object') {
dest[key] = dest[key] || {};
fn(value, dest[key]);
} else {
if (typeof value === 'number') {
dest[key] = (dest[key] || 0) + value;
} else {
dest[key] = value;
}
}
});
return result;
};
return fn(obj, result);
}, {}
);
console.log(addObjects(objA, objB, objC));

How to get values from these objects [duplicate]

This question already has answers here:
One liner to flatten nested object
(19 answers)
Closed 1 year ago.
I am trying to achieve it Like a:1,b:2:,c:3,e:4,g:5,h:6
But not getting success.
Facing error this. But is the best way to do it.
const input = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: {
g: 5,
h: 6
}
}
}
const getValue = (values) => {
for (let i in Object.keys(values)) {
if (Object.keys(values[Object.keys(values)[i]]).length > 0) {
console.log('v', Object.keys(values)[i])
getValue(Object.keys(values)[i])
} else {
// console.log(Object.keys(values)[i],Object.values(values)[i])
}
}
}
getValue(input)
You can iterate through each key of object and for object value recursively call your getValue() function.
const input = { a:1, b:2, c:3, d:{ e:4, f:{ g:5, h:6 } } }
const getValue = (values) => {
for (const key of Object.keys(values)) {
if(typeof values[key] === 'object' && values[key] !== null) {
getValue(values[key]);
} else {
console.log(`${key}: ${values[key]}`);
}
}
}
getValue(input);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use recursion to get the desired result.
const input = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: {
g: 5,
h: 6,
},
},
};
const result = {};
function getValues(obj) {
for (let key in obj) {
if (typeof obj[key] !== `object`) result[key] = obj[key];
else getValues(obj[key]);
}
}
getValues(input);
console.log(result);
Edited : you can do something like this
const input = {a:1,b:2,c:3,d:{e:4,f:{g:5,h:6 }}}
Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}(input))
//{a: 1, b: 2, c: 3, e: 4, g: 5, …}
you can see more details here

create variables from an object

I'm working on a project where I get an object in input like this one :
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
and I need to create some variables to get to this output :
const a = "somestring"
const b = 42
const c.d = "foo"
const c.e = "bar"
const f[0] = 1
const f[1] = 2
I got a result with this code :
for (const [k1, v1] of Object.entries(obj)) {
if (typeof v1 === "object") {
if (Array.isArray(v1)) {
for (const [k2, v2] of Object.entries(v1)) {
console.log(`const ${k1}[${k2}] = ${v2}`);
}
} else {
for (const [k2, v2] of Object.entries(v1)) {
console.log(`const ${k1}.${k2} = ${v2}`);
}
}
} else {
console.log(`const ${k1} = ${v1}`);
}
}
But when I get an object more complex like this one :
const obj = {
a: [
{
b: 'lorem'
},
{
c: 'ipsum'
}
],
d: {
e: {
f : 'foobar'
}
}
};
My output look like this :
const a[0] = [object Object]
const a[1] = [object Object]
const d.e = [object Object]
I can't find any relevant solutions. Is there a solution or npm package for this?
There is a feature called destructuring docs click here
This feature as the docs say will help you create new variables from a nested object.
Taking a object which is nested you can access its leaf values and assign them directly to vars like this:
const o = {
a: 'a',
b: {
c : 'c',
d: {
e: 'e'
}
}
};
const {a ,b : { c, d: {e} }} = o;
alert(a);
alert(c);
alert(e);
Edit: it works with arrays as well not objects only
You can do it with eval function in JS:
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
var log = console.log;
for (let key in obj) {
//log(key);
eval(`var ${key} = obj.${key}`);
}
log(a);
log(b);
log(c);
log(f);
I think you want something like this:
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
const parse = (obj, prefix = '', isArray=false) => {
Object.entries(obj).forEach(([k, v]) => {
if (typeof v === 'object') parse(v, `${k}`, Array.isArray(v))
else {
const value = (typeof v === 'string') ? `"${v}"` : v;
const before = isArray ? '[' : prefix ? '.' : '';
const after = isArray ? ']' : '';
console.log(`const ${prefix}${before}${k}${after} = ${value}`)
}
});
}
parse(obj);

obj1 undefined in an algorithm for deep comparison

JS CODE:
function deepEqual(obj1, obj2) {
f = false; //comparison result
if (Object.keys(obj1).join("") === Object.keys(obj2).join("")) { //checking if properties are equal
var table = Object.keys(obj1);
for (let entry of table) {
console.log("entry",entry); //outputs value
console.log("obj1",obj1);
console.log("obj1.entry",obj1.entry); // why is it undefined(if I write obj1.value it outputs 10)
if (obj1.entry == obj2.entry) {
f = true;
} else {
f = false;
break;
}
}
}
return f;
}
console.log(deepEqual({value:10},{value:10}));
Lot of issue with code, you can simplify it as below.
function deepEqual(obj1 = null, obj2 = null) {
if (obj1 === null || obj2 === null) return false;
if (typeof obj1 !== "object") return obj1 == obj2;
if (Object.keys(obj1).length !== Object.keys(obj2).length) return false;
for (let key in obj1) {
const result = deepEqual(obj1[key], obj2[key]);
if (!result) return false;
}
return true;
}
console.log(
deepEqual(
{ a: 10, value: 10, b: { c: 10 } },
{ b: { c: 10 }, value: 10, a: 10 }
)
);
console.log(
deepEqual(
{ a: 10, value: 10, b: { c: 10 } },
{ b: { c: 10, a: 1 }, value: 10, a: 10 }
)
);

Categories

Resources