Minwu Yu
Minwu Yu

Reputation: 311

simplify the nested condition for loop in javascript

I have my current ugly code to filter an array with specific requirements, is there any better ways to simplify the code by using arrow function or such in order to beautify and shorten the code? tks.

const NewTraitSet = [
    {
        "ValueSet": [
            {
                "Units": null, 
                "Type": "description A", 
                "Value": "description A"
            }, 
            {
                "Units": null, 
                "Type": "description B", 
                "Value": "description B"
            },
            {
                "Units": null, 
                "Type": "risk category", 
                "Value": "Decreased Risk"
            }
        ], 
        "TraitInterpretation": "TraitInterpretation", 
        "TraitCategory": "Health"
    },{
        "ValueSet": [
            {
                "Units": null, 
                "Type": "description A", 
                "Value": "description A"
            }, 
            {
                "Units": null, 
                "Type": "description B", 
                "Value": "description B"
            },
            {
                "Units": null, 
                "Type": "risk category", 
                "Value": "Increased Risk"
            }
        ], 
        "TraitInterpretation": "TraitInterpretation", 
        "TraitCategory": "DD Health", 
    }
]

const result = []
function fun(item, index) {
    for (var key in item) {
        if (key == "ValueSet") {
            for (var obj in item[key]) {
                if (item[key][obj]["Type"] == "risk category" && item[key][obj]["Value"] == "Decreased Risk") {
                    result.push(item)
                }
            }
        }
    }
    return result
}

NewTraitSet.forEach(fun)
// sort traits by name
result.sort((a, b) => (a.TraitCategory > b.TraitCategory ? 1 : -1))

console.log(result)

I'm pretty new to javascript and not so sure how to use arrow function in my case, some advices will be brilliant. Or if there is better solution to get the same result, I will be more than happy to learn from it, tks.

Upvotes: 0

Views: 140

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386560

I used your code with some annotations.

const
    newTraitSet = [{ ValueSet: [{ Units: null, Type: "description A", Value: "description A" }, { Units: null, Type: "description B", Value: "description B" }, { Units: null, Type: "risk category", Value: "Decreased Risk" }], TraitInterpretation: "TraitInterpretation", TraitCategory: "Health" }, { ValueSet: [{ Units: null, Type: "description A", Value: "description A" }, { Units: null, Type: "description B", Value: "description B" }, { Units: null, Type: "risk category", Value: "Increased Risk" }], TraitInterpretation: "TraitInterpretation", TraitCategory: "DD Health" }],
    result = [];

function fun(item) { // remove unused variables
    //for (var key in item) { // remove this, because you need only a single property
    if (!("ValueSet" in item)) return; // return early, if "ValueSet" not exists in rhe object
    // if (key == "ValueSet") {// remove check, because no iteration over the keys
    for (let obj of item.ValueSet) { // use `of` for the values and key directly
        if (obj.Type == "risk category" && obj.Value == "Decreased Risk") { // dot notation for known property
            result.push(item);
        }
    }
    //}
    //}
    // return result; // makes no sense in `forEach`. the return value is never used
}

newTraitSet.forEach(fun);

result.sort((a, b) => a.TraitCategory.localeCompare(b.TraitCategory ? 1 : -1)); // sort by strings

console.log(result);

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370699

Because your output array is composed of elements of your input array, use .filter. Since you're also only concerned with the ValueSet key, you only need to check that key, you don't need to iterate over all of an object's keys.

Then, you need to check if any of the elements in the array passes a test, and if so, push the whole object. The right method to perform such a test is .some:

const NewTraitSet=[{ValueSet:[{Units:null,Type:"description A",Value:"description A"},{Units:null,Type:"description B",Value:"description B"},{Units:null,Type:"risk category",Value:"Decreased Risk"}],TraitInterpretation:"TraitInterpretation",TraitCategory:"Health"},{ValueSet:[{Units:null,Type:"description A",Value:"description A"},{Units:null,Type:"description B",Value:"description B"},{Units:null,Type:"risk category",Value:"Increased Risk"}],TraitInterpretation:"TraitInterpretation",TraitCategory:"DD Health"}];

const result = NewTraitSet.filter(item => item.ValueSet.some(
  ({ Type, Value }) => Type === 'risk category' && Value === 'Decreased Risk'
));
console.log(result);

Or, if you're not comfortable with destructuring:

const NewTraitSet=[{ValueSet:[{Units:null,Type:"description A",Value:"description A"},{Units:null,Type:"description B",Value:"description B"},{Units:null,Type:"risk category",Value:"Decreased Risk"}],TraitInterpretation:"TraitInterpretation",TraitCategory:"Health"},{ValueSet:[{Units:null,Type:"description A",Value:"description A"},{Units:null,Type:"description B",Value:"description B"},{Units:null,Type:"risk category",Value:"Increased Risk"}],TraitInterpretation:"TraitInterpretation",TraitCategory:"DD Health"}];

const result = NewTraitSet.filter(item => item.ValueSet.some(
  inner => inner.Type === 'risk category' && inner.Value === 'Decreased Risk'
));
console.log(result);

Upvotes: 3

Related Questions