Home > OS >  Sorting by pre defined order with multiple properties
Sorting by pre defined order with multiple properties

Time:10-02

I want to sort attendees based on the key groups which is an array of groups (function like tags). I want to sort by the predefined sortOrder order and then by if main_contact is true if multiple attendees for the same group exist. But I'm really stuck with how to check if a groups.name exists and then sort them efficiently by the predefined order.

const attendees = [
  {
    name: "Peter",
    groups: [{ name: "agency", main_contact: false, stand_in_contact: true }],
  },
  {
    name: "Alex",
    groups: [{ name: "agency", main_contact: true, stand_in_contact: false }],
  },
  {
    name: "Nina",
    groups: [
      { name: "production", main_contact: true, stand_in_contact: false },
    ],
  },
  {
    name: "Christina",
    groups: [
      { name: "client", main_contact: true, stand_in_contact: false },
      { name: "crew", main_contact: false, stand_in_contact: false },
    ],
  },
];

const sortAttendees = (attendees) => {
  const sortOrder = ["agency", "client", "production", "crew"];
  // return sortOrder.indexOf(a.type) - sortOrder.indexOf(b.type);
  if (!attendees || attendees.length == 0) return [];
  return attendees.sort((a, b) => {
    if (a.groups.some((group) => group.name === "agency")) {
      return -1;
    }
    if (a.groups.some((group) => group.name === "client")) {
      return 1;
    }
    if (a.groups.some((group) => group.name === "production")) {
      return 1;
    }
    return 1;
  });
};

Result

const attendees = [
  {
    name: "Alex",
    groups: [{ name: "agency", main_contact: true, stand_in_contact: false }],
  },
  {
    name: "Peter",
    groups: [{ name: "agency", main_contact: false, stand_in_contact: true }],
  },
  {
    name: "Christina",
    groups: [
      { name: "client", main_contact: true, stand_in_contact: false },
      { name: "crew", main_contact: false, stand_in_contact: false },
    ],
  },
  {
    name: "Nina",
    groups: [
      { name: "production", main_contact: true, stand_in_contact: false },
    ],
  },
];

CodePudding user response:

Looks like the groups have to be sorted first, then you can sort attendees.

const attendees = [
    {
      name: "Peter",
      groups: [{ name: "agency", main_contact: false, stand_in_contact: true }],
    },
    {
      name: "Alex",
      groups: [{ name: "agency", main_contact: true, stand_in_contact: false }],
    },
    {
      name: "Nina",
      groups: [
        { name: "production", main_contact: true, stand_in_contact: false },
      ],
    },
    {
      name: "Christina",
      groups: [
        { name: "client", main_contact: true, stand_in_contact: false },
        { name: "crew", main_contact: false, stand_in_contact: false },
      ],
    },
  ];
  const sortOrder = ["agency", "client", "production", "crew"];
  
  const sortAttendees = (attendees, sortOrder) => {
    if ([attendees, sortOrder].some(a => !(a instanceof Array))) return;
    // first, sort the groups:
    attendees.forEach(attendee => attendee.groups.sort((a, b) => sortOrder.indexOf(a.name) - sortOrder.indexOf(b.name) || b.main_contact - a.main_contact));
    // now sort attendees:
    attendees.sort((a, b) => {
      const l = Math.min(a.groups.length, b.groups.length);
      for (let i = 0; i < l;   i) {
        const r = sortOrder.indexOf(a.groups[i].name) - sortOrder.indexOf(b.groups[i].name) || b.groups[i].main_contact - a.groups[i].main_contact;
        if (r) return r;
      }
      return 0;
    });
  };
  
  sortAttendees(attendees, sortOrder);
  
  console.log( attendees )
.as-console-wrapper {top:0; max-height: 100% !important}

CodePudding user response:

In my solution I give each attendee a rank value based on their highest ranked membership in a group and their main_contact status in that group.

const attendees = [
  {
    name: "Peter",
    groups: [{ name: "agency", main_contact: false, stand_in_contact: true }],
  },
  {
    name: "Alex",
    groups: [{ name: "agency", main_contact: true, stand_in_contact: false }],
  },
  {
    name: "Nina",
    groups: [
      { name: "production", main_contact: true, stand_in_contact: false },
    ],
  },
  {
    name: "Christina",
    groups: [
      { name: "client", main_contact: true, stand_in_contact: false },
      { name: "crew", main_contact: false, stand_in_contact: false },
    ],
  },
];

const sortAttendees = (attendees) => {
  const sortOrder = ["agency", "client", "production", "crew"];
  
  const rank = attendee => attendee.groups
    .map(group => sortOrder.indexOf(group.name)*2   1 - group.main_contact)
    .sort()
    [0];
  if (!attendees || attendees.length == 0) return [];
  return attendees.sort((a, b) => rank(a)-rank(b));
};

console.log(sortAttendees(attendees));
.as-console-wrapper {top:0; max-height: 100% !important}

  • Related