Reputation: 1283
I have an array of objects which I have to loop through and group duplicate values by property name "tagColor", then the grouped objects I need to sort by name. I achieved first step I sorted by color, now I need to sort only those groups by name, implementing this in angular 4, typescript
Here is array list
tags = [
{
"tagType": {
"name": "a",
"tagColor": "#0000FF"
}
},
{
"tagType": {
"name": "a",
"tagColor": "#FF0000"
}
},
{
"tagType": {
"name": "c",
"tagColor": "#FF0000",
}
},
{
"tagType": {
"name": "b",
"tagColor": "#FF0000",
}
},
{
"tagType": {
"name": "b",
"tagColor": "#0000FF",
}
}
]
my function that sorts by tagColor:
tags.sort((a, b) => a.tagType.tagColor.localeCompare(b.tagType.tagColor));
this groups by color only, but how also to sort those groups alphabetically?
Upvotes: 3
Views: 1910
Reputation: 565
Compare by color first and then compare by name in the sort function. The compare function returns -1, 0, 1. If the b should come after the a then the function returns a -1 - no sort needed, if the b is equal to the a the function returns a 0 - no sort needed, if the b needs to come before the a then the function returns a 1 - sort needed. Since -1 and 0 evaluate to false and 1 evaluates to true basically the sort function is returning a true needs to be sorted or false does not need to be sorted. So if you compare by color and it needs to be sorted then we pass the colorSort value, if the color doesn't need to be sorted then we pass the nameSort value
tags.sort((a, b) => {
let colorSort = a.tagType.tagColor.localeCompare(b.tagType.tagColor);
let nameSort = a.tagType.name.localeCompare(b.tagType.name);
return (colorSort)? colorSort:nameSort;
});
Upvotes: 1
Reputation: 386654
Beside the given order by color, you could use a defined custom order for the color with an object which reflects the order.
For colors, not found in the object, you could take a default value to move this colors to a defined position, to the start,
(order[a.tagType.tagColor] || -Infinity) - (order[b.tagType.tagColor] || -Infinity)
to the end,
(order[a.tagType.tagColor] || Infinity) - (order[b.tagType.tagColor] || Infinity)
or inbetween.
(colorOrder[a.tagType.tagColor] || 1.5) - (colorOrder[b.tagType.tagColor] || 1.5)
var tags = [{ tagType: { name: "a", tagColor: "#0000FF" } }, { tagType: { name: "a", tagColor: "#FF0000" } }, { tagType: { name: "c", tagColor: "#FF0000" } }, { tagType: { name: "b", tagColor: "#FF0000" } }, { tagType: { name: "b", tagColor: "#0000FF" } }],
colorOrder = { "#0000FF": 1, "#FF0000": 2 };
tags.sort((a, b) =>
colorOrder[a.tagType.tagColor] - colorOrder[b.tagType.tagColor] ||
a.tagType.name.localeCompare(b.tagType.name)
);
console.log(tags);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 2
Reputation: 249706
You can use a single sort call, if the result of comparing tags is 0 you compare by name:
tags.sort((a, b) => {
let result = b.tagType.tagColor.localeCompare(a.tagType.tagColor);
if(result == 0) {
return a.tagType.name.localeCompare(b.tagType.name);
}
return result;
});
Or a more concise but less readable version:
tags.sort((a, b) =>
b.tagType.tagColor.localeCompare(a.tagType.tagColor) // if this is 0 (aka falsy) return the other value
|| a.tagType.name.localeCompare(b.tagType.name));
Upvotes: 7