-3

Suppose if i have an input data like:

[
      {
      name: 'rohan',
      subName: [
        {
          name: 'rohan_abc',
          subName: [
            {
              name: 'rohan_abc_abc',
              subName: []
            }]
        },
          {
          name: 'rohan_abc',
          subName: []
        },{
          name: 'rohan_abc_abc',
          subName: []
        }]
    },
    {
      name: 'rohan',
      subName: [
        {
          name: 'rohan_abc',
          subName: [
            {
              name: 'rohan_abc_abc',
              subName: [{
                    name: 'rohan_abc_abc_abc',
                    subName: []
                  }]
            }]
        },
          {
          name: 'rohan_bcd',
          subName: []
        },{
          name: 'rohan_abc_abc',
          subName: []
        }]
    }]

The output should be like

[
  {
  name: 'rohan',
  count: 2,
  subName: [
    {
      name: 'rohan_abc',
      count: 3,
      subName: [
        {
          name: 'rohan_abc_abc',
          count: 2
          subName: [
            {
              name: 'rohan_abc_abc_abc',
              count: 1
            }]
        }]
    },
     {
      name: 'rohan_abc_abc',
      count: 2
      subName: []
    },
    {
      name: 'rohan_bcd',
      count: 1
    }]
}]

if the same name is repeated in the same layer then the count should increase. Otherwise, the count should remain 1.

In above example: rohan_abc_abc is occurred at 2 different levels so that they have different count at respective level. Hoping to get positive feedbacks. Thank you!!!

  • 2
    What did you try ? –  Sep 16 '21 at 08:49
  • You can use `.reduce` and you already tagged your question with recursion. It seems like you already know how to solve it. – jabaa Sep 16 '21 at 08:50
  • @PhilAndelhofs I have already spent 1 day looking into this :( . Can you please put some insights here. :) I will be grateful! – Rowan Siwakoti Sep 16 '21 at 09:06
  • @RowanSiwakoti of course i will try, gimme some time please. –  Sep 16 '21 at 09:51
  • Does this answer your question? [Counting the occurrences / frequency of array elements](https://stackoverflow.com/questions/5667888/counting-the-occurrences-frequency-of-array-elements), [JavaScript ES6 - count duplicates to an Array of objects](https://stackoverflow.com/questions/49676897/javascript-es6-count-duplicates-to-an-array-of-objects) – jabaa Sep 16 '21 at 10:14
  • You can start counting in the outer layer and recursively count in each `subName`. – jabaa Sep 16 '21 at 10:20

1 Answers1

0

Array Reduce Information on MDN

Array reduce takes 2 parameters, a callback function with 4 arguments and secondly an initial value. The callback functions takes up to 4 arguments previousValue, currentValue, currentIndex, array. we focus on the first two arguments and the initialValue parameter.

Where previousValue is the previous value OR the initial value OR undefined; Where currentValue is the current.

Oke, lets learn reduce!

let arr = [0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE, 0xF];
arr.reduce( ( previousValue, currentValue ) => { return previousValue; });
//returns 0 ( as it should, up to you to figure out why )

Now we will use initialValue, the second parameter of de reduce function.

arr.reduce( ( accumulator, currentValue ) => { 
    accumulator.push(currentValue*2); 
    return accumulator; 
}, []);
// returns [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]

So as you can see, we used the second parameterof the reduce function with a empty new array. We push the current value and multiply times 2. And return of course we return the accumulator/previous value.

So if we apply that logic to your array and do some checks..

aa.reduce((accumulator, currentValue) => {
    // get all names in the accumulator
    let nameMap = accumulator.map((element) => {
        return element.name;
    });
    let indexOfcurrentValueName = nameMap.indexOf(currentValue.name);

    // check if already exist in accymulator
    if (indexOfcurrentValueName > -1) {
        //Is already in
        // concat subName
        accumulator[indexOfcurrentValueName].subName = accumulator[indexOfcurrentValueName].subName.concat( currentValue.subName);
    } else {
        //not in put currentValue in accumulator
        accumulator.push(currentValue);
    }

    return accumulator;
}, []);

if we put this inline function in a function statement and call it after we concat accumulator[indexOfcurrentValueName].subName.reduce( reduceFn, []); than you will get what you want.

Edit 17 Sept 2021:

//the reduce function 
function reduceFn(accumulator, currentValue) {
    // get all names in the accumulator
    let nameMap = accumulator.map((element) => {
        return element.name;
    });
    let indexOfcurrentValueName = nameMap.indexOf(currentValue.name);

    // check if already exist in accymulator
    if (indexOfcurrentValueName > -1) {
        //Is already in
        // concat subName
        accumulator[indexOfcurrentValueName].subName = accumulator[indexOfcurrentValueName].subName.concat( currentValue.subName);
/* ---- */
// this will make the call back to the reduce function but for it's children. this is for level 2,3,4,5,6,7, infinity
    accumulator[indexOfcurrentValueName].subName.reduce( reduceFn, []);

/* ---- */
    } else {
        //not in put currentValue in accumulator
        accumulator.push(currentValue);
    }

    return accumulator;
}

// and here we kick start things this is for level 1
arr.reduce( reduceFn, []);
  • Hi @PhilAndelhofs! Thank you for the instant response but i got a little confused with the last line. You mean to wrap the array.reduce in a function and after concat call the same function recursively? Like following: – Rowan Siwakoti Sep 17 '21 at 08:59
  • `function recurseFna( ) { return array.reduce((accumulator, currentValue) => { // removed code just because of character limitation; accumulator[indexOfcurrentValueName].subName = accumulator[indexOfcurrentValueName].subName.concat( currentValue.subName); accumulator[indexOfcurrentValueName].subName.reduce(recurseFna, []); return accumulator; }, []); }recurseFna( );` – Rowan Siwakoti Sep 17 '21 at 09:02
  • I will insert the code to give you an idea :) –  Sep 17 '21 at 10:28
  • @RowanSiwakoti i did update the anwser with an example, beware this is just an example, this is not the most efficient, sexy code. But this should give you enough to add a count etc... if not feel free to ask more :D –  Sep 17 '21 at 10:35
  • Just curious about one thing, even though it has recursion and making call back to level 2,3,4,5,6,7, infinity. And i think as per you, except the count property this code should give me unique names and subnames maintaining their layer position but by using above code i can see that repetition in subNames and their subNames. Why is only working on first layer even though we are making call recursively? Can you please check it once with the input array and see the output. – Rowan Siwakoti Sep 17 '21 at 11:59
  • @RowanSiwakoti i see it, what the problem is, if you add the count you can clearly see what is going on, i have a very busy day today, but i will explain things more as soon as possible, so you can understand why you do not have unique objects. –  Sep 17 '21 at 12:26