Reputation: 1249
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
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
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
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