AlexFF1
AlexFF1

Reputation: 1283

Group duplicates values in javascript array together, then sort those groups by their value name ascending

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?

enter image description here

Upvotes: 3

Views: 1910

Answers (3)

Harry Chilinguerian
Harry Chilinguerian

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

Nina Scholz
Nina Scholz

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

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

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

Related Questions