0

I get my response array with duplicate values. Id, Name and Cod, but there are itens differents like Indicator. So I grouped my array using reduce. This is my array:

let myArray = [  
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":2,      
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":2,
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  }
]

console.log("My Array with duplicate values:" )
console.log(myArray)

    var group_to_values = myArray.reduce(function (obj, item) {
      obj[item.cod] = obj[item.cod] || [];
      obj[item.cod].push(item.indicator);
      return obj;
    }, {});

    var groups = Object.keys(group_to_values).map(function (key) {
      return {
        cod: key,
        indicatorItem: group_to_values[key]
      };
    });

console.log("My Array grouped:" )
console.log(groups)

However, since reduce uses only 1 item (key) I lose the other values as: Id, Name

So, I tried to use a .map() and .filter() to find for items like id andname using cod as a reference, but I did not get much success. I'm going somewhere, but I do not know where :/

As I'm comparing item by item, the end of my return will always be the last item (cod) in my array. I understand that so the return is only the cod 00CC

This is my code:

let returnedItens = null

myArray.map(itemArray => {
  returnedItens = groups.filter(itemGroup => {
      if (itemArray.cod == itemGroup.cod) {
        return {
          id: itemArray.id,
          name: itemArray.name,
          cod: itemGroup.cod,
          indicator: itemGroup.indicator,
        }
      }
    })
  })

So, I would like to get this return with my code above:

[  
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":[  
      {  
        "idIndicator":2,
        "name":"MY-SECOND-NAME",
      },
      {  
        "idIndicator":3,
        "name":"MY-FIST-NAME",
      }
    ]
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":[  
      {  
        "idIndicator":2,
        "name":"MY-SECOND-NAME",
      },
      {  
        "idIndicator":3,
        "name":"MY-FIST-NAME",
      }
    ]
  }
]

Please, someone can help me? How I can do it?

Zkk
  • 741
  • 13
  • 29
  • If you would like to stick to using functional programming concept , see my answer below. – tnkh Mar 20 '19 at 07:46

4 Answers4

2

You can use an object with keys representing the data you'd like to reduce onto, namely, the .cod property. After grouping, use Object.values() to convert your objects back into an array. Time complexity is linear.

let myArray = [ { "id":1, "name":"NAME1", "cod":"00CC", "indicator":{ "idIndicator":2, "name":"MY-SECOND-NAME", } }, { "id":1, "name":"NAME1", "cod":"00CC", "indicator":{ "idIndicator":3, "name":"MY-FIST-NAME", } }, { "id":5, "name":"DWWW", "cod":"200CC", "indicator":{ "idIndicator":2, "name":"MY-SECOND-NAME", } }, { "id":5, "name":"DWWW", "cod":"200CC", "indicator":{ "idIndicator":3, "name":"MY-FIST-NAME", } } ];
const result = {};

for (const o of myArray) {
  if (!(o.cod in result)) {
    result[o.cod] = o;
    result[o.cod].indicator = [o.indicator];
  }
  else {
    result[o.cod].indicator.push(o.indicator);
  }
}

console.log(Object.values(result));
ggorlen
  • 44,755
  • 7
  • 76
  • 106
1

Array.prototype.reduce is the correct way to do what you want.

Array.prototype.filter and Array.prototype.map both serve different purpose. Besides, you are using them incorrectly in your code snippet. (Please read the referenced docs)

.map is to transform every array value.

.filter is to extract certain array value(s).

.reduce is to return a single output by accessing every array value.

Below is a working code and explanation:

let myArray = [  
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":2,      
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":2,
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  }
]

// If you don't understand what are `acc` and `curr`, read the doc I referenced above
const ret = myArray.reduce((acc, curr) => {

  // Get the index of the obj with same id, name and cod
  const indexOfSameObj = acc.findIndex(obj => {
    return obj.id === curr.id
        && obj.name === curr.name
        && obj.cod === curr.cod
  });
  
  if (indexOfSameObj >= 0){
    // If same obj exists, push next.indicator to the same obj
    acc[indexOfSameObj].indicator.push(curr.indicator);
  } else {
    // If same obj doesn't exist, push new obj with new structure to reduced array
    acc.push({
      id: curr.id,
      name: curr.name,
      cod: curr.cod,
      indicator: [curr.indicator]  // Make `.indicator` an array
    });
  }

  // Return the new reduced array
  return acc;

}, []  /* This empty array is the initial value of reduced array */);

console.log(ret);
yqlim
  • 6,898
  • 3
  • 19
  • 43
1

This is the simplest code that I can come with. It simply loops an array and match items and if found delete from inner array as well as outer array to remove duplicates.

let myArray = [  
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":2,      
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":2,
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  }
]
const copyMyArray = [...myArray];

myArray.forEach((arr, i) => {
  copyMyArray.forEach((ar, index) => {
    let same = arr.id === ar.id && arr.name === ar.name && arr.cod === ar.cod;
    if(same && index !== i) {
      arr.indicator = [ arr.indicator, ar.indicator];
      // do not loop next time
      copyMyArray.splice(index, 1);
      // remove from first array 
      myArray.splice(index, 1)
    }

  })
})
console.log(myArray)
Prakash Kandel
  • 1,043
  • 6
  • 12
0

Credits to ggorlen for introducing Object.values method. To achieve a more elegant and faster solution, you can stick to using reduce method with my following code :

let myArray = [  
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":2,      
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":1,
    "name":"NAME1",
    "cod":"00CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":2,
      "name":"MY-SECOND-NAME",
    }
  },
  {  
    "id":5,
    "name":"DWWW",
    "cod":"200CC",
    "indicator":{  
      "idIndicator":3,
      "name":"MY-FIST-NAME",
    }
  }
]

let newArray = myArray.reduce(function(prev,next){

    let key = next.cod;
    if (!prev[key]){
       prev[key] = next;
       prev[key]["indicator"]=[prev[key]["indicator"]]
    } else {
       prev[key]["indicator"].push(next["indicator"])
    }
    return prev
},[])

console.log(Object.values(newArray))
tnkh
  • 1,749
  • 2
  • 14
  • 30
  • 1
    Think of reduce like mapping, except reduce takes in two or more values and return a new state of values. By checking whether the new array has the duplicated keys or not, we can determine whether we need to create a new object or push to an existing key. – tnkh Mar 20 '19 at 08:06
  • Thank you so much. This way is reaaly very simple to read and understand! – Zkk Mar 21 '19 at 19:18
  • 1
    @Zkk, no problem. Glad to help :) – tnkh Mar 22 '19 at 01:05