循环遍历两个对象数组以将匹配值推送到新数组在 React 中不起作用,但在 JS Fiddle 中起作用

Posted

技术标签:

【中文标题】循环遍历两个对象数组以将匹配值推送到新数组在 React 中不起作用,但在 JS Fiddle 中起作用【英文标题】:Looping through two object arrays to push matching values to a new array doesn't work in React but does in JS Fiddle 【发布时间】:2018-09-23 08:48:16 【问题描述】:

我有两个长度不同的数据集。我需要遍历两个数组并将匹配的玩家 ID 的照片 url 推送到一个新数组。我在 API 数据已加载到我的 React 组件后执行此操作,因此这似乎不是数据尚未加载的问题。我可以console.log 两个数据集并看到它们已成功从 API 返回。所有这些都适用于 JS Fiddle(下面的链接),但不适用于 React。所以我很难追查到底发生了什么。

这是我的数据集(显然都被缩短了):

这个对象数组是从一个包含所有玩家信息的 API 端点返回的,例如 ID、照片 URL 等(这是 1200 多个对象):

playerInfo = [
 PlayerID: 123, PhotoURL: url123,
 PlayerID: 345, PhotoURL: url345,
 PlayerID: 678, PhotoURL: url678,
 PlayerID: 910, PhotoURL: url910,
 PlayerID: 1112, PhotoURL: "url1112",
 PlayerID: 1213, PhotoURL: "url1213"
];

此数据从列出当前领导者的单独 API 端点返回(返回前 40 名领导者):

playerIDs = [123, 345, 678, 910]

不幸的是,这个排行榜数据不包括照片 URL 和返回的玩家 ID,所以我必须比较两个数组中的玩家 ID,然后从上面匹配的 playerInfo 数组中推送 PhotoURL。

我的方法如下(我可能会为此使用某种类型的 ES6 功能,所以如果是这种情况,请告诉我。):

let leaderPhotos = [];

for(let i = 0; i < playerInfo.length; i++) 
  if(playerInfo[i].PlayerID === playerIDs[i]) 
    leaderPhotos.push(playerInfo[i].PhotoURL);
  

对此我的想法是,即使playerIDs 数组比PlayerInfo 数组短,将循环设置为PlayerInfo 数组的长度将允许比较较短的PlayerIDs 排行榜数组PlayerInfo 对象数组中的每个玩家 ID,因为任何玩家都可以在任何给定时间出现在排行榜上。如果玩家 ID 在两个数组中匹配,它会将 PlayerInfo 对象的照片 URL 值推送到一个数组,然后我可以使用该数组加载最高领导者的照片。由于循环按顺序通过排行榜PlayerIDs,因此返回的照片 URL 是按排行榜的顺序。

它在JS Fiddle 中工作。 您可以在控制台中看到它只推送匹配玩家 ID 的照片 URL。完美,正是我想要的。

但是,当在负责处理 API 数据的 React 组件中应用同样的事情时,在逻辑运行正常后,我会在控制台中返回一个空数组。我可以console.log 两个返回的 API 数据集来查看我是否成功地让数据恢复工作。

我搞砸了,决定看看是否将两个数组索引都设置为一个值:

let leaderPhotos = [];

      if(playerInfo[0].PlayerID === playerIDs[0]) 
        leaderPhotos.push(playerInfo[0].PhotoURL);
       else 
         return false;
       console.log(leaderPhotos);

果然,这将按预期将匹配对的照片 url 推送到 leaderPhotos 没有 for 循环。我很难理解为什么 for 循环不起作用,即使在 JS Fiddle 中它证明这应该返回所需的结果。提前感谢您的任何提示!

【问题讨论】:

你能提供你的反应组件代码吗? 【参考方案1】:

简洁版

const leaderPhotos = playerIDs.map(id => 
    playerInfo.find(( PlayerID ) => PlayerID === id).PhotoURL
);

注意:只是为了让您知道这是一个嵌套循环。其中map 是通过领导委员会的循环,find 是通过玩家的循环。时间复杂度为 O(n * m),其中 n 是用户总数,m 是领导委员会的长度。

虽然如果用户总数不是很大,那应该没关系,只要代码看起来干净且易于理解,那就更好了(:

如果您有 HUGE 数量的用户,并且您希望拥有最高效的代码。您应该做的是将您的 playerInfo 存储在一个地图/对象中,其中键是 playerId,值是 playerURL。这样,它只需要遍历你的对象一次,并且对玩家照片进行 O(1) 检索。

高效版

const playerMap = ;

playerInfo.forEach((player) => 
  playerMap[player.PlayerID] = player.PhotoURL;
);

const leaderPhotos = playerIDs.map(leaderId => playerMap[leaderId]);

其时间复杂度最多为 O(n),其中 n 是玩家的数量。

【讨论】:

您的第一个解决方案在 JSFiddle 中出现错误。你能检查一下代码吗? 糟糕!谢谢!我主要是在尝试做伪代码,并没有看到 JSFiddle 这对我来说非常完美。我感谢您的解释。【参考方案2】:

试试这个

let leaderPhotos = playerInfo.filter(plr => playerIDs.indexOf(plr.PlayerID) !== -1).map( t => t.PhotoURL);

【讨论】:

【参考方案3】:

确保您的两个数组具有基于playerId 的相同顺序。

否则,你需要使用两个循环:

let leaderPhotos = [];

for(let i = 0; i < playerInfo.length; i++) 
  for(let j = 0; j < playerIDs.length; j++ )
    if(playerInfo[i].PlayerID === playerIDs[j]) 
      leaderPhotos.push(playerInfo[i].PhotoURL);
    

【讨论】:

【参考方案4】:

我认为这是与其他答案相比最短的解决方案:

let leaderPhotos = playerInfo.filter((info) => playerIDs.includes(info.PlayerID)).map(id => id.PhotoURL);

【讨论】:

以上是关于循环遍历两个对象数组以将匹配值推送到新数组在 React 中不起作用,但在 JS Fiddle 中起作用的主要内容,如果未能解决你的问题,请参考以下文章

以空格为分隔符的爆炸数组并将值推送到新数组

比较 2 个对象的值并将值推送到一个对象数组

如何遍历一组 Firebase Firestore 文档并将值推送到数组中

比较并将正确的值推送到 JavaScript/TypeScript 中的对象数组

将值推送到辅助数组javascript

如何在 Vue 中求和并推送到匹配的对象