Reputation: 1
I have below Object with me.
car = [{
Acc: "X1",
primary: true,
Name: "Park Street",
Date: "2018/01/01"
},{
Acc: "X1",
primary: false,
Name: "Park Street 2",
Date: "2018/03/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 3",
Date: "2018/01/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 4",
Date: "2018/05/01"
}];
I have to get only one element from each group of "Acc". One element for each of Acc:"X1" and Acc:"X2". Logic to find that should be if primary: true, then select that element from the group else pick the one having latest Date: value.
I do understand this requirement can be achievable using underscore js but I am new in this and can't figure out the relevant way.
Can someone please help me here?
Upvotes: 0
Views: 88
Reputation: 27202
if primary: true, then select that element from the group else pick the one having latest Date: value
As per the above statement there is only one primary:true
in each group (X1
or X2
). If my understanding is correct you can try below code :
// Input object
var car = [{
Acc: "X1",
primary: true,
Name: "Park Street",
Date: "2018/01/01"
}, {
Acc: "X1",
primary: false,
Name: "Park Street 2",
Date: "2018/03/01"
}, {
Acc: "X2",
primary: false,
Name: "Park Street 3",
Date: "2018/01/01"
}, {
Acc: "X2",
primary: false,
Name: "Park Street 4",
Date: "2018/05/01"
}];
// fetch the primary:true objects from the Input array.
var primaryTrueArray = car.filter(obj => {
if (obj.primary === true) {
return obj;
}
});
// filtered out the primary:true objects from the Input array based on the primaryTrueArray.Hence, we will get all primary:false.
var filteredOutPrimaryTrue = car.filter(obj => primaryTrueArray.filter(item => item.Acc != obj.Acc));
// Fetch the latest date from the group who has primary:false from the filteredOutPrimaryTrue.
var latestDateFromGroup = filteredOutPrimaryTrue.sort(function(a,b){
if (a.Date < b.Date)
return 1;
else if (a.Date == b.Date)
return 0;
else
return -1;
});
// Concatenate both the arrays "primaryTrueArray & latestDateFromGroup" into single one.
var finalResult = primaryTrueArray.concat([latestDateFromGroup[0]]);
// Desired output.
console.log(finalResult);
Upvotes: 0
Reputation: 5434
Since you have mentioned Underscore, I understand you can use external libraries. This is the same approach as @Keith did, but using Lodash instead.
Also, this should work with all browsers.
var car = [{
Acc: "X1",
primary: true,
Name: "Park Street",
Date: "2018/01/01"
},{
Acc: "X1",
primary: false,
Name: "Park Street 2",
Date: "2018/03/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 3",
Date: "2018/01/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 4",
Date: "2018/05/01"
}];
var sorted = _.orderBy(car, ['primary', 'Date'], ['desc', 'desc']);
var groupedSorted = _.groupBy(sorted, 'Acc');
var result = _.flatMap(groupedSorted, function(o) { return o[0]; });
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Upvotes: 0
Reputation: 24191
One way to do this, is first group by Acc
, and then within the group sort by primary
& Date
descending, and then just pick the first of each group.
eg.
const car = [{
Acc: "X1",
primary: true,
Name: "Park Street",
Date: "2018/01/01"
},{
Acc: "X1",
primary: false,
Name: "Park Street 2",
Date: "2018/03/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 3",
Date: "2018/01/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 4",
Date: "2018/05/01"
}];
//lets group
const grouped = car.reduce((a, v) => {
if (!a[v.Acc]) a[v.Acc] = [];
a[v.Acc].push(v);
return a;
}, {});
//now for each group sort by primary, and then Date
const result = Object.values(grouped).map((g) => {
g.sort((a, b) => b.primary - a.primary || b.Date.localeCompare(a.Date));
return g[0]; //now sorted, pick first.
});
console.log(result);
Another more efficient way, might be just to keep track of the best inside an object literal..
eg..
const car = [{
Acc: "X1",
primary: true,
Name: "Park Street",
Date: "2018/01/01"
},{
Acc: "X1",
primary: false,
Name: "Park Street 2",
Date: "2018/03/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 3",
Date: "2018/01/01"
},{
Acc: "X2",
primary: false,
Name: "Park Street 4",
Date: "2018/05/01"
}];
const best = {};
car.forEach((c) => {
const b = best[c.Acc] = best[c.Acc] || c;
if (b.primary) return;
if (c.Date.localeCompare(best.Date) < 0) best[c.Acc] = c;
});
console.log(Object.values(best));
Upvotes: 2