Martin Carre
Martin Carre

Reputation: 1249

NodeJS: Extracting duplicates from Array

I'd need your help... I'm sorry if the question has already been asked but I can't seem to find a suitable answer for my problem: I'm trying to extract (not remove) the list of the duplicates from my array.

ultimately, the main objective is to keep only one of the duplicated objects (in the array) with the higher profit...

Here's a simple example of my array:

var arr = [
  {
    mkBase: "test",
    mkComp: "test1",
    invest: { profit: 10 },
    availability: true,
    option: 1
  },
  {
    mkBase: "test",
    mkComp: "test1",
    invest: { profit: 15 },
    availability: false,
    option: 2
  },
  {
    mkBase: "test1",
    mkComp: "test",
    invest: { profit: 8 },
    availability: true,
    option: 3
  },
  {
    mkBase: "test2",
    mkComp: "test",
    invest: { profit: 6 },
    availability: true,
    option: 4
  },
  {
    mkBase: "test",
    mkComp: "test2",
    invest: { profit: 6 },
    availability: true,
    option: 5
  },
  {
    mkBase: "test",
    mkComp: "test3",
    invest: { profit: 7 },
    availability: true,
    option: 6
  },
  {
    mkBase: "test",
    mkComp: "test3",
    invest: { profit: 10 },
    availability: true,
    option: 7
  },
  {
    mkBase: "test3",
    mkComp: "test4",
    invest: { profit: 10 },
    availability: true,
    option: 8
  }
];

And I managed to extract a list of almost all duplicates using:

for (var i = 0; i < arr.length; i++) {
  if (_.uniqBy(arr, "mkBase").indexOf(arr[i]) == -1) {
    console.log("[SAME BASE]: " + JSON.stringify(arr[i], null, 2));
  } else if (_.uniqBy(arr, "mkComp").indexOf(arr[i]) == -1) {
    console.log("[SAME COMP]: " + JSON.stringify(arr[i], null, 2));
  }
}

And here's the result:

[SAME BASE]: {
  "mkBase": "test",
  "mkComp": "test1",
  "invest": {
    "profit": 15
  },
  "availability": false,
  "option": 2
}
[SAME COMP]: {
  "mkBase": "test2",
  "mkComp": "test",
  "invest": {
    "profit": 6
  },
  "availability": true,
  "option": 4
}
[SAME BASE]: {
  "mkBase": "test",
  "mkComp": "test2",
  "invest": {
    "profit": 6
  },
  "availability": true,
  "option": 5
}
[SAME BASE]: {
  "mkBase": "test",
  "mkComp": "test3",
  "invest": {
    "profit": 7
  },
  "availability": true,
  "option": 6
}
[SAME BASE]: {
  "mkBase": "test",
  "mkComp": "test3",
  "invest": {
    "profit": 10
  },
  "availability": true,
  "option": 7
}

The Lodash method (_.uniqBy) is keeping one of the duplicates in the main Array, and, in order to ultimately get the best (_.maxBy(arr, 'profit')) of the duplicates, I'd need it with the other duplicates.

I'm not sure I'm very clear, but if you need any clarification please let me know!

Thanks in advance to you all!

********** EDIT ************* As suggested by stasovlas you'll find below the expected result and why the other objects in the array were removed:

var result = [
  {
    mkBase: "test",
    mkComp: "test1",
    invest: { profit: 15 },
    availability: false,
    option: 2
  },
  {
    mkBase: "test1",
    mkComp: "test",
    invest: { profit: 8 },
    availability: true,
    option: 3
  },
  {
    mkBase: "test3",
    mkComp: "test4",
    invest: { profit: 10 },
    availability: true,
    option: 8
  }
];

var removed = [
  //Reason: Same Base **and** Comp mk as option 2 && Profit is too low versus option 2
  {
    mkBase: "test",
    mkComp: "test1",
    invest: { profit: 10 },
    availability: true,
    option: 1
  },
  //Reason: Same Comp mk as option 3 && Profit is too low versus option 3
  {
    mkBase: "test2",
    mkComp: "test",
    invest: { profit: 6 },
    availability: true,
    option: 4
    //Reason: Same Base mk as option 2 && Profit is too low versus option 2
  },
  {
    mkBase: "test",
    mkComp: "test2",
    invest: { profit: 6 },
    availability: true,
    option: 5
  },
  //Reason: Same Base mk as option 2 && Profit is too low versus option 2 
  {
    mkBase: "test",
    mkComp: "test3",
    invest: { profit: 7 },
    availability: true,
    option: 6
  },
  //Reason: Same Base mk as option 2 && Profit is too low versus option 2 
  {
    mkBase: "test",
    mkComp: "test3",
    invest: { profit: 10 },
    availability: true,
    option: 7
  }
];

Upvotes: 1

Views: 590

Answers (3)

stasovlas
stasovlas

Reputation: 7416

i'm not sure in my question understanding, but here my solution:

const res = _.reduce(arr, (result, item) => {
    const same = _.find(result, r => _.some([
        r.mkBase === item.mkBase,
        r.mkComp === item.mkComp
    ])); // find same already added item

    if (same === undefined) {
        return _.concat(result, item); // just push item   
    }

    if (same.invest.profit >= item.invest.profit) {
        return result; // do nothing if profit is less then already added
    }

    return _.chain(result) // remove item with smaller profit and push item with higher profit
        .reject({ mkBase: same.mkBase, mkComp: same.mkComp })
        .concat(item)
        .value();
}, []);

Upvotes: 1

kofman
kofman

Reputation: 106

var sameBase = {}, sameComp = {};

arr.forEach(item => {
    let existingBase = sameBase[item.mkBase];

    if ( ( existingBase === undefined ) ||  ( existingBase.invest.profit < item.invest.profit ) ) {
            sameBase[item.mkBase] = item;  
    } 

    existingComp = sameComp[item.mkComp];
    if ( ( existingComp === undefined ) ||  ( existingComp.invest.profit < item.invest.profit ) ) {
        sameComp[item.mkComp] = item;  
    }
});

var sameBaseArr = toArr(sameBase);
var sameCompArr = toArr(sameComp);

console.log("SAME BASE: " + JSON.stringify(sameBaseArr, true));
console.log("SAME COMP: " + JSON.stringify(sameCompArr, true));

function toArr(map) {
    let arr = [];
    for (var key in map) {
        arr.push(map[key]);
    }   
    return arr;     
}

Upvotes: 1

Ly&#231;ann H.
Ly&#231;ann H.

Reputation: 113

Try this (not tested, but the logic can help):

var mkBases = [], mkComps = [];

for (var i = 0; i < arr.length; i++) {
    var actualBase = arr[i].mkBase;
    var actualComp = arr[i].mkComp;

    if (typeof mkBases[actualBase] !== 'undefined') {
        mkBases[actualBase] = {getAllIndexes(arr, actualBase)}
    }

    if (typeof mkComps[actualComp] !== 'undefined') {
        mkComps[actualComp] = {getAllIndexes(arr, actualComp)}
    }
}

function getAllIndexes(arr, val) {
    var indexes = [], i = -1;
    while ((i = arr.indexOf(val, i+1)) != -1){
        indexes.push(i);
    }
    return indexes;
}

Now you can iterate over mkBases and mkComp to get your duplicates.

Upvotes: 0

Related Questions