Сортировка по заранее определенному порядку с несколькими свойствами

#javascript #sorting

Вопрос:

Я хочу сортировать участников на основе ключа groups , который представляет собой массив групп (функция, подобная тегам). Я хочу отсортировать по предопределенному sortOrder порядку, а затем по тому, верно ли значение main_contact, если существует несколько участников для одной и той же группы. Но я действительно застрял в том, как проверить, есть ли groups.name существует, а затем эффективно сортирует их по заданному порядку.

 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;
  });
};
 

Результат

 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 },
    ],
  },
];
 

Ответ №1:

Похоже, сначала нужно отсортировать группы, а затем вы сможете сортировать участников.

 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} 

Ответ №2:

В своем решении я даю каждому участнику значение ранга, основанное на его членстве в группе с наивысшим рейтингом и статусе main_contact в этой группе.

 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}