Мне нужна помощь в упрощении кода, который сравнивает различные свойства объектов

#javascript #arrays #javascript-objects

Вопрос:

У меня есть сильное подозрение, что мой код слишком неуклюж и может быть написан более лаконично и эффективно. Цель состоит в том, чтобы сравнить массив объектов (представляющих игроков), чтобы найти игрока с самым высоким свойством majorityScore. Если несколько игроков имеют одинаковый высокий балл, затем сравните фракции соавторов с картой (приоритетная карта), чтобы определить, кто победит.

 players = [
  {
    majorityScore: 4,
    faction: 'AR'
  },
  {
    majorityScore: 8,
    faction: 'MOU'
  },
  {
    majorityScore: 2,
    faction: 'MOB'
  },
  {
    majorityScore: 8,
    faction: 'I'
  }
];

const priorityMap = {
  'MOB': 1,
  'I': 2,
  'MOU': 3,
  'AR': 4,
  'S' : 0
}

let winner;
let highScore = -1;
let duplicates = [];
for(let i = 0; i < players.length; i  ){
  if(players[i].majorityScore > highScore){
    highScore = players[i].majorityScore;
    winner = players[i]
    duplicates = [winner];
  } else if (players[i].majorityScore === highScore){
    duplicates.push(players[i]);
  };
}
if(duplicates.length > 1){
  let highFactionScore = duplicates.reduce((a,v) => {
    if(priorityMap[v.faction] > a){
      a = priorityMap[v.faction];
    }
    return a;
  }, 0);
  let winningFaction = Object.keys(priorityMap).find((k) => {
    return priorityMap[k] === highFactionScore;
  });
  winner = duplicates.filter((v) => {
    return v.faction === winningFaction
  })
}
 

Ответ №1:

Поскольку вы уменьшаете массив объектов в один объект, здесь можно использовать функцию уменьшения: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Вместо того, чтобы проверять фракции после получения игроков с наибольшим большинством голосов, вы можете проверять фракции всякий раз, когда в конечном итоге сравниваете игроков с одинаковым большинством голосов.

 let winner = players.reduce((accum, currVal) => {
    if (accum.majorityScore < currVal.majorityScore) {
        return currVal;
    } else if (accum.majorityScore > currVal.majorityScore) {
        return accum;
    } else {
        return priorityMap[accum.faction] > priorityMap[currVal.faction] ? accum : currVal
    }
});
 

Ответ №2:

Вот несколько более короткий метод. Он использует временный объект для ведения словаря, в котором баллы являются ключами. По мере повторения мы добавляем значение priorityMap[faction] свойства score и изменяем его только в том случае, если значение больше, чем сохраненное.

 const players=[{majorityScore:4,faction:"AR"},{majorityScore:8,faction:"MOU"},{majorityScore:8,faction:"MOU12"},{majorityScore:8,faction:"MOU20"},{majorityScore:2,faction:"MOB"},{majorityScore:2,faction:"MOB2"},{majorityScore:8,faction:"I"}],priorityMap={MOB:1,I:2,MOU:3,MOB2:4,AR:4,S:0,MOU12:21,MOU20:22};

function getGroups(arr) {

  // Create the temp object
  // We'll be using the scores as keys, and using
  // the value in priorityMap as the value
  // As we iterate we check the new priorityMap value
  // against the old one
  const temp = {};

  // Iterate over the players array
  return arr.reduce((acc, c) => {
    const { majorityScore: score, faction } = c;

    // If the accumulator object doesn't have a key that
    // matches the score, add a new object
    acc[score] = (acc[score] || { majorityScore: score, faction });

    // If the new value of priorityMap[faction] is
    // greater than the one stored in temp
    // update the faction in the accumulator for that score
    if (priorityMap[faction] > temp[score]) {
      acc[score].faction = faction;
    }

    // Update the temp object with the
    // priorityMap[faction] value
    temp[score] = priorityMap[faction];

    // Return the accumulator for the next iteration
    return acc;
  }, {});
}

console.log(getGroups(players));