循环遍历两个对象数组以将匹配值推送到新数组在 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 中起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何遍历一组 Firebase Firestore 文档并将值推送到数组中