简体   繁体   中英

Increment a parameter in a javascript recursive function

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

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

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))

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM