0
\$\begingroup\$

I have a nested object and I would like to calculate the number of times the property 'error'. I am able to go n levels deep and find the count. Is there a better solution than mine?

const data = {
 "item1": {
 "value": 88,
 "error": false
 },
 "item2": {
 "value": 651,
 "error": false
 },
 "item3": false,
 "item4": [],
 "item5": "",
 "item6": "",
 "item7": false,
 "item8": {
 "error": true
 },
 "item9": {
 "value": [],
 "error": true
 },
 "item10": {
 "value": [],
 "error": true
 },
 "item11": {
 "value": [],
 "error": true
 },
 "item12": false,
 "item13": {
 "subItem1": {
 "name": "Country",
 "groups": {},
 "instances": [],
 "error": true
 },
 "subItem2": {
 "name": "Group",
 "groups": {},
 "instances": [],
 "error": true
 },
 "subItem3": {
 "name": "Product",
 "groups": {},
 "instances": [],
 "error": true
 }
 }
}
function traverseAndFlatten(currentNode, target, flattenedKey) {
 for (var key in currentNode) {
 if (currentNode.hasOwnProperty(key)) {
 var newKey;
 if (flattenedKey === undefined) {
 newKey = key;
 } else {
 newKey = flattenedKey + '.' + key;
 }
 var value = currentNode[key];
 if (typeof value === "object") {
 traverseAndFlatten(value, target, newKey);
 } else {
 target[newKey] = value;
 }
 }
 }
}
function flatten(obj) {
 var flattenedObject = {};
 traverseAndFlatten(obj, flattenedObject);
 return flattenedObject;
}
var flattened = flatten(data);
const keys = _.keys(flattened);
const errorCount = _.map(keys, key => {
 let count = 0;
 if (key.includes('.error') && flattened[key]) {
 count++
 }
 return count
})
console.log(_.sumBy(errorCount))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Feb 18, 2021 at 2:26
\$\endgroup\$
8
  • \$\begingroup\$ Given that the code uses lodash, when you state "I am open to use lodash as well." did you actually mean that you are open to not using lodash? \$\endgroup\$ Commented Feb 18, 2021 at 14:12
  • \$\begingroup\$ I am open to using lodash. I will fix the OP \$\endgroup\$ Commented Feb 18, 2021 at 14:28
  • \$\begingroup\$ Are you also open to vanilla JS i.e. without lodash? \$\endgroup\$ Commented Feb 18, 2021 at 14:33
  • 1
    \$\begingroup\$ please clarify what qualifies as "better" - fewer lines of code? faster? uses less memory? \$\endgroup\$ Commented Feb 18, 2021 at 16:11
  • 1
    \$\begingroup\$ Maybe not the best idea, but could be easiest to implement: count = 0; JSON.stringify(data, function (x, y) { if (x === 'error' && y) count++; return y; }); alert(count); \$\endgroup\$ Commented Feb 19, 2021 at 6:27

1 Answer 1

1
\$\begingroup\$

The comment recommending JSON.stringify is a bit faster, but it is in the range of <1 microsecond

const data = {
 "item1": {
 "value": 88,
 "error": false
 },
 "item2": {
 "value": 651,
 "error": false
 },
 "item3": false,
 "item4": [],
 "item5": "",
 "item6": "",
 "item7": false,
 "item8": {
 "error": true
 },
 "item9": {
 "value": [],
 "error": true
 },
 "item10": {
 "value": [],
 "error": true
 },
 "item11": {
 "value": [],
 "error": true
 },
 "item12": false,
 "item13": {
 "subItem1": {
 "name": "Country",
 "groups": {},
 "instances": [],
 "error": true
 },
 "subItem2": {
 "name": "Group",
 "groups": {},
 "instances": [],
 "error": true
 },
 "subItem3": {
 "name": "Product",
 "groups": {},
 "instances": [],
 "error": true
 }
 }
}
function traverseAndFlatten(currentNode, target, flattenedKey) {
 for (var key in currentNode) {
 if (currentNode.hasOwnProperty(key)) {
 var newKey;
 if (flattenedKey === undefined) {
 newKey = key;
 } else {
 newKey = flattenedKey + '.' + key;
 }
 var value = currentNode[key];
 if (typeof value === "object") {
 traverseAndFlatten(value, target, newKey);
 } else {
 target[newKey] = value;
 }
 }
 }
}
function flatten(obj) {
 var flattenedObject = {};
 traverseAndFlatten(obj, flattenedObject);
 return flattenedObject;
}
let startTime = performance.now()
var flattened = flatten(data);
const keys = _.keys(flattened);
const errorCount = _.map(keys, key => {
 let count = 0;
 if (key.includes('.error') && flattened[key]) {
 count++
 }
 return count
})
let count =_.sumBy(errorCount)
let endTime = performance.now()
console.log(count)
console.log(`Call to count error took ${endTime - startTime} milliseconds`)
startTime = performance.now()
count = 0;
JSON.stringify(data, function (x, y) { if (x === 'error' && y) count++; return y; });
endTime=performance.now()
console.log(count)
console.log(`Call to count error 2 took ${endTime - startTime} milliseconds`)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

answered Jan 5, 2023 at 16:37
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.