Сделаем функцию сравнения () более элегантной - PullRequest
2 голосов
/ 29 октября 2019

У меня есть этот код:

function compare (a, b) {
  let comparison = 0;
  if (a.essentialsPercentage < b.essentialsPercentage) {
    comparison = 1;
  } else if (a.essentialsPercentage > b.essentialsPercentage) {
    comparison = -1;
  } else {
    if (a.skillsNicePercentage < b.skillsNicePercentage) {
      comparison = 1;
    } else if (a.skillsNicePercentage > b.skillsNicePercentage) {
      comparison = -1;
    } else {
      if (a.startDate > b.startDate) {
        comparison = 1
      } else if (a.startDate < b.startDate) {
        comparison = -1
      }
    }
  }
  return comparison;
}

Какой самый элегантный способ написать это? В данный момент это выглядит не очень хорошо.

Ответы [ 6 ]

3 голосов
/ 29 октября 2019

Предполагая, что это используется в качестве функции сравнения для Array.prototype.sort(), имеет значение только знак результата, он не должен быть конкретно -1 или 1. Таким образом, вместо if и else вы можете просто вычесть числа.

compare(a, b) {
    let comparison = b.essentialPercentage - a.essentialPercentage;
    if (comparison == 0) {
        comparison = b.skillsNicePercentage - a.skillsNicePercentage;
        if (comparison == 0) {
            comparison = a.startDate - b.startDate;
        }
    }
    return comparison;
}

Если любое из свойств является строкой, а не числом, вы можете использовать localCompareвместо вычитания.

2 голосов
/ 29 октября 2019

Эта крошечная функция (или эквивалентный <=> оператор ) является, пожалуй, наиболее очевидным недостатком стандартной библиотеки js:

// returns 1 if a > b, -1 if a < b, 0 if a == b
let cmp = (a, b) => (a > b) - (a < b)

После того, как вы ее определили, цепочечные сравненияочень легко:

compare = (a, b) =>
    cmp(a.essentialsPercentage, b.essentialsPercentage)
    || cmp(a.skillsNicePercentage, b.skillsNicePercentage)
    || cmp(a.startDate, b.startDate)
0 голосов
/ 29 октября 2019

Попробуйте

function compare(a, b) {
  let c= b.essentialsPercentage - a.essentialsPercentage;
  let d= b.skillsNicePercentage - a.skillsNicePercentage;
  let e= a.startDate - b.startDate

  return Math.sign(c||d||e);
}

function compareNew(a, b) {
  let c= b.essentialsPercentage - a.essentialsPercentage;
  let d= b.skillsNicePercentage - a.skillsNicePercentage;
  let e= a.startDate - b.startDate

  return Math.sign(c||d||e);
}

function compareOld(a, b) {
  let comparison = 0;
  if (a.essentialsPercentage < b.essentialsPercentage) {
    comparison = 1;
  } else if (a.essentialsPercentage > b.essentialsPercentage) {
    comparison = -1;
  } else {
    if (a.skillsNicePercentage < b.skillsNicePercentage) {
      comparison = 1;
    } else if (a.skillsNicePercentage > b.skillsNicePercentage) {
      comparison = -1;
    } else {
      if (a.startDate > b.startDate) {
        comparison = 1
      } else if (a.startDate < b.startDate) {
        comparison = -1
      }
    }
  }
  return comparison;
}



// TESTS

a={essentialsPercentage:2,skillsNicePercentage:2,startDate:new Date(0)};
tests=[
  {essentialsPercentage:2,skillsNicePercentage:2,startDate:new Date(0)},
  {essentialsPercentage:2,skillsNicePercentage:2,startDate:new Date(+10000)},
  {essentialsPercentage:2,skillsNicePercentage:2,startDate:new Date(-10000)},
  {essentialsPercentage:2,skillsNicePercentage:2,startDate:new Date()},
  {essentialsPercentage:2,skillsNicePercentage:3,startDate:new Date()},
  {essentialsPercentage:2,skillsNicePercentage:1,startDate:new Date()},
  {essentialsPercentage:3,skillsNicePercentage:1,startDate:new Date()},  
  {essentialsPercentage:1,skillsNicePercentage:1,startDate:new Date()},    
]

tests.map(b=> console.log(`old: ${compareNew(a,b)}   new:${ compareOld(a,b)}`));
0 голосов
/ 29 октября 2019

Вы можете обобщить это в более простую функцию, которая принимает массив имен полей и сортирует общий массив по этим полям по порядку. Приведенный ниже код черпает вдохновение из библиотеки базы данных Mongoose и позволяет префиксу - в имени поля сортировать по убыванию, а не по возрастанию по умолчанию. Это также работает только для чисел и строк;если вы хотите поддерживать другие типы, вам придется расширить код.

function multiSort(fields) {
    return (a,b) => {
        let result = 0;
        for (let i = 0; result === 0 && i < fields.length; ++i) {
          let fieldName = fields[i];
          if (fieldName.charAt(0) === '-') {
              fieldName = fieldName.substring(1);
              if (typeof a[fieldName] === 'string') {
                  result = b[fieldName].localeCompare(a[fieldName]);
              }
              else {
                result = b[fieldName] - a[fieldName];
              }
          } else {
              if (typeof a[fieldName] === 'string') {
                  result = a[fieldName].localeCompare(b[fieldName]);
              }
              else {
                result = a[fieldName] - b[fieldName];
              }
          }
        }

        return result;
    };
}

Эта функция более высокого порядка будет принимать массив полей и возвращать функцию, которая сортирует эти поля по порядку,для строк и чисел, необязательно с именем поля, начинающимся с -, чтобы отсортировать это поле в порядке убывания. Вы бы использовали это так:

someArrayValue.sort(multisort(['essentialsPercentage', 'skillsNicePercentage', '-startDate']));
0 голосов
/ 29 октября 2019

Основываясь на логике в вашем сравнении, это должно работать

function compare (a, b) {

  let comparison = a.skillsNicePercentage == b.skillsNicePercentage ? (a.startDate - b.startDate) : b.skillsNicePercentage - a.skillsNicePercentage
  let comparison1 = a.essentialsPercentage == b.essentialsPercentage ? b.skillsNicePercentage - a.skillsNicePercentage : comparison
  return comparison1;

}
0 голосов
/ 29 октября 2019

Если вы хотите, вы можете использовать оператор switch, чтобы каждый ваш случай был красивым и организованным. Это будет более «чистый» метод, но не обязательно самый правильный. Смотрите эту ветку -> https://stackoverflow.com/a/2312837/11263228

В качестве альтернативы, вы можете создать отдельные функции, которые будут проверять каждый ваш случай. Например, имея функцию, которая принимает в качестве параметров a.skillsNicePercentage и b.skillsNicePercentage и возвращает true / false. Это будет чище, а также многоразовым!

...