Как отфильтровать массив объектов по дубликатам и свойствам?

#javascript #arrays #filter

Вопрос:

У меня есть массив, подобный этому:

 let data = [
    {
        name: 'foo',
        score: 10,
    },
    {
        name: 'bar',
        score: 20
    },
    {
        name: 'foo',
        score: 15,
    },
];
 

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

Ответ №1:

Вы можете использовать reduce для этого.

 const highScores = data.reduce((memo, entry) => {
  if (!memo[entry.name] || memo[entry.name] < entry.score) {
    memo[entry.name]=entry.score
  }
  return memo; 
},{})
 

Ответ №2:

Reduce() идеально подходит для такого рода вещей.

 let data = [{
    name: 'foo',
    score: 10,
  },
  {
    name: 'bar',
    score: 20
  },
  {
    name: 'foo',
    score: 15,
  },
];

let hs = data.reduce((b, a) => {
    let i = b.findIndex(e => e.name === a.name)
    if (i > -1) b[i].score = Math.max(b[i].score, a.score)
    else b.push(a)
    return b;
  }, []);
console.log(hs) 

Ответ №3:

Я бы предложил что-то вроде этого:

 const data = [
    {
        name: 'foo',
        score: 10,
    },
    {
        name: 'bar',
        score: 20
    },
    {
        name: 'foo',
        score: 15,
    },
];

// We'll keep track of the max scores here
const maxScore = {};
// Iterating with destructuring to directly access name/score
for (const { name, score } of data) {
    const currentScore = maxScore[name];
    if (!currentScore) {
        // No score saved yet, save this one
        maxScore[name] = score;
    } else if (currentScore < score) {
        // This score is higher than the saved one
        maxScore[name] = score;
    } else {
        // Score is lower (or equal) so do nothing
    }
}
console.log(maxScore);

// If you want to convert it back to an array:
const list = Object.entries(maxScore).map(
    // Object.entries returns [key, value][]
    // so we map it, extract the key/value (name/score) from each
    // pair and create an object from it which we return
    ([name, score]) => ({ name, score }));
console.log(list); 

Ответ №4:

 let data = [
  {
    name: "foo",
    score: 10,
  },
  { name: "bar", 
    score: 20 },
  {
    name: "foo",
    score: 15,
  },
];

const highestIndex = data.reduce(result, {name, score}) => {
  result[name] = !result[name] || score > result[name] 
  ? score 
  : result[name];
  return resu<
}, {})
 

если вам нужен результат в той же структуре, что и данные, просто преобразуйте результат
в массив с помощью сопоставления Object.entries:

 const highestScores = 
  Object
  .entries(highestIndex)
  .map(([name, score]) => ({name, score}))
 

Ответ №5:

Вы можете решить эту проблему с reduce() помощью или вы можете использовать классический шаблон решения.

С уменьшением()

 const data = [{ name: 'foo', score: 10 }, { name: 'bar', score: 20 }, { name: 'foo', score: 15 } ];
const highsObj = data.reduce((acc, currentItem) => {
    if (!acc[currentItem.name] || acc[currentItem.name].score < currentItem.score) {
        acc[currentItem.name] = currentItem;
    }
    return acc;
}, {})

// As an array
const highsArray = Object.values(highsObj);
console.log(highsArray);
 

Классический узор

 const data = [{ name: 'foo', score: 10 }, { name: 'bar', score: 20 }, { name: 'foo', score: 15 } ];
const highScores = {};
for (const item of data) {
    const { name, score } = item;
    const currentValue = highScores[name];
    if (!currentValue || currentValue.score < score) {
        highScores[name] = item;
    }
}

// As an array
const highScoresArray = Object.values(highScores);
console.log(highScoresArray);
 

Ответ №6:

В чем проблема с перебором массива для начала? Бог не убивает котенка каждый раз , когда вы решаете проблему в JavaScript без вызова array.filter или array.reduce , вы знаете 🙂

Вот еще одно восхитительно нечистое решение (извините, кошечки, ничего личного), использующее удивительную пластичность JavaScript (использование объекта, такого как ассоциативный массив).

 var data = [
  { name: 'foo', score: 10 },
  { name: 'bar', score: 20 },
  { name: 'foo', score: 15 },
];

var high_score = {};
for (record of data) { // note it's the ES6 "of", not the ill-fated legacy "in" !!!
   if ((high_score[record.name] ?? 0) < record.score) { 
      high_score[record.name] = record.score;
   }
}


// "high_score" is just an object with a property named after each player
console.log(high_score)
>>> Object { foo: 15, bar: 20 }

// This object can be accessed like an associative array (a circa 1995
// ancestor of a dictionary, if you like), in a pretty intuitive way:    
console.log(high_score["foo"])    
>>> 15
console.log(high_score["bar"])
>>> 20