J'ai deux ensembles de données dont la longueur varie. J'ai besoin de parcourir les deux tableaux et de pousser l'URL de la photo des ID de joueur correspondants vers un nouveau tableau. Je le fais après le chargement des données de l'API dans mon composant React, il ne semble donc pas que les données ne soient pas encore chargées. Je peux console.log les deux ensembles de données et voir qu'ils sont correctement renvoyés par l'API. Tout cela fonctionne dans JS Fiddle (lien ci-dessous), mais pas React. J'ai donc du mal à retracer ce qui se passe.

Voici mes ensembles de données (tous ont évidemment été raccourcis):

Ce tableau d'objets est renvoyé à partir d'un point de terminaison API qui contient toutes les informations du joueur, telles que l'ID, les URL des photos, etc., etc. (il s'agit de plus de 1200 objets):

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"}
];

Ces données sont renvoyées à partir d'un point de terminaison API distinct qui répertorie les leaders actuels (renvoie les 40 principaux leaders):

playerIDs = [123, 345, 678, 910]

Malheureusement, ces données de classement n'incluent pas l'URL de la photo avec les ID de joueur retournés, je dois donc comparer les ID de joueur dans les deux tableaux, puis pousser la PhotoURL à partir du tableau playerInfo correspondant ci-dessus.

Mon approche est la suivante (je pourrais probablement utiliser un type de fonctionnalité ES6 pour cela, alors faites-le moi savoir si c'est le cas.):

let leaderPhotos = [];

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

Ma pensée pour cela est que même si le tableau playerIDs est plus court que le tableau PlayerInfo, définir la boucle sur la longueur du tableau PlayerInfo permettra le classement PlayerIDs plus court tableau à comparer avec chaque ID de joueur dans le tableau d'objets PlayerInfo car n'importe quel joueur peut être dans le classement à tout moment. Si un ID de joueur correspond dans les deux tableaux, il pousse la valeur de l'URL de la photo de l'objet PlayerInfo vers un tableau, que je peux ensuite utiliser pour charger dans les photos de premier plan. Étant donné que la boucle passe dans le classement PlayerIDs, les URL des photos renvoyées sont dans l'ordre du classement.

Ici, cela fonctionne dans JS Fiddle. Vous pouvez voir dans la console qu'elle pousse uniquement l'URL de la photo des ID de joueur correspondants. Parfait, juste ce que je veux.

Cependant, lorsque cette même chose est appliquée à l'intérieur du composant React responsable de la gestion des données API, je récupère un tableau vide dans la console après que la logique a exécuté son cours. Je peux console.log les deux ensembles de données d'API retournés pour voir que je récupère les données avec succès.

Je déconnais et j'ai décidé de voir si la définition des deux index de tableau sur une valeur fonctionnerait comme suit:

let leaderPhotos = [];

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

Et bien sûr, cela poussera l'url de la photo de la paire correspondante vers leaderPhotos comme prévu sans la boucle for. J'ai du mal à comprendre pourquoi la boucle for ne fonctionne pas, même si dans JS Fiddle cela prouve que cela devrait retourner les résultats souhaités. Merci pour tous les conseils à l'avance!

1
maison.m 13 avril 2018 à 07:42

4 réponses

Meilleure réponse

Version courte et propre

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

Remarque: Juste pour vous faire savoir qu'il s'agit d'une boucle imbriquée. Où map est une boucle à travers le conseil d'administration et find est une boucle à travers les joueurs. La complexité temporelle est O (n * m) n est le nombre total d'utilisateurs et m est la longueur du conseil d'administration.

Bien que si le nombre total d'utilisateurs n'est pas énorme, cela ne devrait pas avoir d'importance et tant que le code semble propre et compréhensible, ce serait toujours mieux (:

Si vous avez un nombre ÉNORME d'utilisateurs et que vous souhaitez disposer du code le plus efficace . Ce que vous devez faire est de stocker votre playerInfo dans une carte / un objet où la clé est le playerId et la valeur est le playerURL. De cette façon, il n'a besoin de parcourir vos objets qu'une seule fois et a une récupération O (1) pour les photos du joueur.

Version efficace

const playerMap = {};

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

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

La complexité temporelle de ceci est au plus O (n) n est le nombre de joueurs.

3
Kenneth Truong 13 avril 2018 à 06:02

Assurez-vous que vos deux tableaux ont le même ordre basé sur playerId.

Sinon, vous devez utiliser deux boucles:

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);
    }
}
0
Alex 13 avril 2018 à 05:04

Je pense que c'est donc la solution la plus courte possible par rapport aux autres réponses:

let leaderPhotos = playerInfo.filter((info) => playerIDs.includes(info.PlayerID)).map(id => id.PhotoURL);
0
Yash Thakur 13 avril 2018 à 05:25

Essaye ça

let leaderPhotos = playerInfo.filter(plr => playerIDs.indexOf(plr.PlayerID) !== -1).map( t => t.PhotoURL);
1
prabhatojha 13 avril 2018 à 05:03