1

I have the following data stored in a variable:

let categories = [
    {
    name: "a",
    selected: false,
    nodes: [
        {
        name: "aa",
        selected: false
      },
      {
        name: "ab",
        selected: true
      },
      {
        name: "ac",
        selected: true
      },
      {
        name: "ad",
        selected: false
      }
    ]
  },
  {
    name: "b",
    selected: false,
    nodes: [
        {
        name: "ba",
        selected: false
      },
      {
        name: "bb",
        selected: true
      },
      {
        name: "bc",
        selected: true
      },
      {
        name: "bd",
        selected: false
      }
    ]
  }
];

I want to count how much item has selected = true.
So I create the following function:

function getSelected(categories, counter = 0) {
    for (let index = 0; index < categories.length; index++) {
        const category = categories[index];
    if (category.selected) {
        counter++;
    }
    if (category.nodes && category.nodes.length) {
        category.nodes.forEach(cat => getSelected([cat], counter));
    }
    }
  return counter;
}

but it always returns 0.

A working jsFiddle

3 Answers 3

3

You could take a recursive reduce of the nodes and count selected.

const
    countSelected = (s, o) => (o.nodes || []).reduce(countSelected, s + o.selected);

let categories = [{ name: "a", selected: false, nodes: [{ name: "aa", selected: false }, { name: "ab", selected: true }, { name: "ac", selected: true }, { name: "ad", selected: false }] }, { name: "b", selected: false, nodes: [{ name: "ba", selected: false }, { name: "bb", selected: true }, { name: "bc", selected: true }, { name: "bd", selected: false }] }],
    count = categories.reduce(countSelected, 0);

console.log(count);

Sign up to request clarification or add additional context in comments.

2 Comments

PS: the depth of nodes is unknown, so reduce won't work if we had deeper nodes.
it works here for all nested nodes properties, because is uses a recursion. please have a look to the reduce of countSelected.
3

It is because Number (and other primitives) arguments to function are duplicated, it create a whole new variable initialized with the arguments value.

what you can do is either use the return value of your function and sum it, or you can use Objects as arguments as they are send by reference, so you keep the same object :

let categories = [{name: "a",selected: false,nodes: [{name: "aa",selected: false},{name: "ab",selected: true},{name: "ac",selected: true},{name: "ad",selected: false}]},{name: "b",selected: false,nodes: [{name: "ba",selected: false},{name: "bb",selected: true},{name: "bc",selected: true},{name: "bd",selected: false}]}]

function getSelectedWithObject(categories, counter = {val: 0}) {
    for (let index = 0; index < categories.length; index++) {
        const category = categories[index]
        if (category.selected) {
            counter.val++
        }
        if (category.nodes && category.nodes.length) {
            category.nodes.forEach(cat => getSelectedWithObject([cat], counter))
        }
    }
    return counter.val
}

function getSelectedWithReturnValue(categories) {
    let counter = 0
    for (let index = 0; index < categories.length; index++) {
        const category = categories[index]
        if (category.selected) {
            counter++
        }
        if (category.nodes && category.nodes.length) {
            category.nodes.forEach(cat => counter += getSelectedWithReturnValue([cat]))
        }
    }
    return counter
}

console.log(getSelectedWithObject(categories))
console.log(getSelectedWithReturnValue(categories))

Comments

1

counter is an integer so it's passed by value here. Make the counter the result you want to get back from the function and there you go:

function getSelected(categories) {
    var counter = 0;
    for (let index = 0; index < categories.length; index++) {
        const category = categories[index];
        if (category.selected) {
           counter++;
        }
        if (category.nodes && category.nodes.length) {
           category.nodes.forEach(cat => counter += getSelected([cat]));
        }
    }
    return counter;
}

console.log(getSelected(categories));

Comments

Your Answer

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.