过滤对象数组

时间:2018-08-02 14:02:10

标签: javascript arrays object filter

我正在尝试过滤对象数组。我可以根据自己的情况进行过滤并获得结果,但是我想在过滤后采取措施。

heroes = [

//match1  
{ 
    player1: { name: "Batman", score: 1},
    player2: { name: "Ironman", score: 3}
},
//match2 
{
    player1: { name: "Thor", score: 0},
    player2: { name: "Superman", score: 2}
},
//match3  
{
    player1: { name: "Superman", score: 4},
    player2: { name: "Batman", score: 1}
},
//match4  
{
    player1: { name: "Ironman", score: 3},
    player2: { name: "Thor", score: 5}
}

];

我正在提供示例方案。例如,我想计算所有比赛中蝙蝠侠的总得分。但是正如您所看到的,蝙蝠侠有时是玩家1,有时是玩家2。

这就是为什么我发现这样的原因:

    //While Batman player1, find all matches and sum scores
      var player1matches = heroes.filter(match => match.player1.name.indexOf("Batman") > -1);
      var player1scores= player1matches .reduce(((acc, match) => acc + match.player1.score), 0);

    //While Batman player2, find all matches and sum scores
        var player2matches = heroes.filter(match => match.player2.name.indexOf("Batman") > -1);
        var player2scores= player1matches .reduce(((acc, match) => acc + match.player2.score), 0);

    //Total Batman scores 
        var batmanScore = player1scores+ player2scores

但这肯定不是一个好的解决方案,因为player1对象中将有很多道具,而我将使用这些数据。

简而言之,我在player1和player2对象中有很多道具。我想根据特定名称对这些数据求和/订阅/计数。

等待您的建议。

6 个答案:

答案 0 :(得分:1)

老实说,这个问题有点令人困惑,但是按照您所说的,这是一个解决方案。另外,我相信您的数组声明不正确,如果您想要匹配的数组,请尝试以下操作:

matches = [
    { 
        player1: { name: "Batman", score: 1},
        player2: { name: "Ironman", score: 3}
    },
    {
        player1: { name: "Thor", score: 0},
        player2: { name: "Superman", score: 2}
    },
    {
        player1: { name: "Superman", score: 4},
        player2: { name: "Batman", score: 1}
    },
    {
        player1: { name: "Ironman", score: 3},
        player2: { name: "Thor", score: 5}
    }

];

然后,您可以进行比赛,并且如果其中任一球员为batman,请创建一个总和并将其积分加到其中。

var batmanTotalPoints = 0;

heroes.forEach(function(match) {
    if(match.player1.name === 'Batman') batmanTotalPoints += match.player1.score;
    else if (match.player2.name === 'Batman') batmanTotalPoints += match.player2.score;
})

但是这里所有其他答案也将非常有效!使用reduce也是一个不错的选择。

答案 1 :(得分:1)

您可以直接减少数组以获得最终分数。

function calculateScoreForPlayer(heroes, playerName){
  return heroes.reduce( (result, currentHero) => {
    const p1 = currentHero.player1;
    const p2 = currentHero.player2;
    if(p1.name === playerName){
      result.score += p1.score;
    }
    if(p2.name === playerName){
      result.score += p2.score;
    }

    return result;
  } , { score : 0}).score;
}

编辑:要从评论中回答问题

原始答案只是做事的一个简短方法

function calculateScoreForPlayer(heroes, playerName) {
    const result = heroes.reduce(
        (result, currentHero) => {
            const p1 = currentHero.player1;
            const p2 = currentHero.player2;
            if (p1.name === playerName) {
                result.score += p1.score;
            }
            if (p2.name === playerName) {
                result.score += p2.score;
            }

            return result;
        }, { score: 0 });

    return result.score;
}

我没有将结果存储在临时变量result中,而是返回了实际对象。

假设输出得分为3,那么如果您不做.score部分,则会得到一个对象{ score: 3 } 如果您这样做.score,则会得到3作为输出。

希望有帮助

答案 2 :(得分:0)

对于每场比赛,我们都会检查每位球员。对于每个玩家,我们执行以下两项操作之一:

  1. 如果玩家的姓名与要求的姓名相符,我们将获得分数
  2. 如果玩家的名字不匹配,我们取0

然后我们获得每场比赛的总和。然后,我们得到所有匹配项的总和。这样就得出了该名称的总得分。

heroes = [
  match1 = { 
      player1: { name: "Batman", score: 1},
      player2: { name: "Ironman", score: 3}
  },
  match2 = {
      player1: { name: "Thor", score: 0},
      player2: { name: "Superman", score: 2}
  },
  match3 = {
      player1: { name: "Superman", score: 4},
      player2: { name: "Batman", score: 1}
  },
  match4 = {
      player1: { name: "Ironman", score: 3},
      player2: { name: "Thor", score: 5}
  }
];

const getNameScore = (input, name) => input
  .map(match => Object.keys(match)
    .map(key => match[key].name === name ?
      match[key].score : 0 
    ).reduce((prev, curr) => prev + curr, 0)
  ).reduce((prev, curr) => prev + curr, 0)
  
console.dir(getNameScore(heroes, "Ironman"))
console.dir(getNameScore(heroes, "Batman"))
console.dir(getNameScore(heroes, "Thor"))

答案 3 :(得分:0)

function getScore(name) {
  return heroes.map(x => { //Map each match to either a score or NULL
    if (x.player1.name === name) return x.player1.score;
    if (x.player2.name === name) return x.player2.score;
    return null;
  })
  .filter(x => null !== x) //Remove NULL
  .reduce((acc, current) => acc + current); //Sum
}

console.log(getScore('Superman')); // => 6
console.log(getScore('Batman')); // => 2
console.log(getScore('Thor')); // => 5

在此示例中,我们将每个匹配项映射到得分(整数)或 NULL 。之后,我们通过过滤来删除所有NULL值,然后通过将它们加在一起将它们减小为单个整数。这给了我们最后一个整数-总分。

答案 4 :(得分:0)

我可以建议一个幼稚的解决方案,因为它无效,因此您可以重构提议的数组。 这是一个工作示例:

// it's actually matchs and not heroes
// at least for me :)
matchs = [
  // match 1
  [{
      name: "Batman",
      score: 1
    }, // player 1
    {
      name: "Ironman",
      score: 3
    }
  ], // player 2

  // match 2
  [{
      name: "Thor",
      score: 0
    }, // player 1
    {
      name: "Superman",
      score: 2
    }
  ], // player 2

  // match 3
  [{
      name: "Superman",
      score: 4
    }, // player 1
    {
      name: "Batman",
      score: 1
    }
  ], // player 2

  // match 4
  [{
      name: "Ironman",
      score: 3
    }, // player 1
    {
      name: "Thor",
      score: 5
    }
  ], // player 2

]

function heroScore(name) {

  let score = 0;

  // loop through matchs
  matchs.forEach(match => {
    if (match[0].name === name ||
      match[1].name === name) {
      score += match[0].name === name ? match[0].score : match[1].score;
    }
  });

  return score;
}

console.log("Batman : " + heroScore("Batman"));
console.log("Thor : " + heroScore("Thor"));
console.log("Superman : " + heroScore("Superman"));
console.log("Ironman : " + heroScore("Ironman"));

此解决方案效率不高,因为它会解析``匹配''数组中的每个元素,如果数组太长,则可能会消耗资源;

答案 5 :(得分:0)

您有很多选择,但是如果您需要其他属性,则可能需要修改数据结构:

let matches = getData();


//create a new player and match key for each player and only an array of players
let flattened = []
matches.forEach((match,match_num)=>{
  for(let player in match){
    let new_player = Object.assign({},match[player]);
    new_player.player = player;
    new_player.match  = match_num+1;
    flattened.push(new_player)
  }
});
console.log('flattened:\n',flattened);


// Batman
const batman = flattened.filter(player=>player.name.toLowerCase()=='batman')
console.log('batman:\n',batman);

// Sums
const scores = flattened.reduce((acc,player)=>{
  if (typeof acc[player.name] == 'undefined')
    acc[player.name]=0;
  acc[player.name] += +player.score;
  return acc;
},{});
console.log('scores:\n', scores);



function getData() {
  return [

    //match1  
    {
      player1: {
        name: "Batman",
        score: 1
      },
      player2: {
        name: "Ironman",
        score: 3
      }
    },
    //match2 
    {
      player1: {
        name: "Thor",
        score: 0
      },
      player2: {
        name: "Superman",
        score: 2
      }
    },
    //match3  
    {
      player1: {
        name: "Superman",
        score: 4
      },
      player2: {
        name: "Batman",
        score: 1
      }
    },
    //match4  
    {
      player1: {
        name: "Ironman",
        score: 3
      },
      player2: {
        name: "Thor",
        score: 5
      }
    }

  ];
}