Цикл по двум массивам объектов для передачи совпадающих значений в новый массив не работает в React, но работает в JS Fiddle

У меня есть два набора данных разной длины. Мне нужно перебрать оба массива и вставить URL-адрес фотографии соответствующего идентификатора игрока в новый массив. Я делаю это после, данные API загружены в мой компонент React, поэтому, похоже, это не связано с тем, что данные еще не загружены. Я могу console.info обоих наборов данных и видеть, что они успешно возвращаются из API. Все это работает в JS Fiddle (ссылка ниже), но не в React. Так что мне сложно отследить, что происходит.

Вот мои наборы данных (все они явно сокращены):

Этот массив объектов возвращается из конечной точки API, которая содержит всю информацию о плеере, такую ​​как идентификатор, 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-адреса фотографий с возвращенными идентификаторами игроков, поэтому мне нужно сравнить идентификаторы игроков в обоих массивах, а затем нажать PhotoURL из указанного выше соответствующего массива playerInfo.

Мой подход заключается в следующем (я, вероятно, мог бы использовать для этого какую-то функцию 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, поскольку любой проигрыватель может быть в таблице лидеров в любой момент. Если идентификатор игрока совпадает в обоих массивах, он помещает значение URL-адреса фотографии объекта PlayerInfo в массив, который я затем могу использовать для загрузки в фотографии лучших лидеров. Поскольку цикл проходит через таблицу лидеров PlayerIDs, возвращенные URL-адреса фотографий располагаются в порядке таблицы лидеров.

Здесь он работает в JS Fiddle. Вы можете видеть в консоли, что он выталкивает только URL-адреса фотографий соответствующих идентификаторов игроков. Отлично, именно то, что я хочу.

Однако, когда то же самое применяется внутри компонента React, ответственного за обработку данных API, я получаю пустой массив в консоли после того, как логика выполнит его. Я могу console.info оба возвращенных набора данных API, чтобы убедиться, что я успешно возвращаю данные для работы.

Я возился и решил посмотреть, будет ли установка обоих индексов массива на значение работать так:

let leaderPhotos = [];

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

И, конечно же, это подтолкнет URL-адрес подходящей пары к фотографии в leaderPhotos, как и ожидалось без в цикле for. Мне трудно понять, почему цикл for не работает, хотя в JS Fiddle он доказывает, что он должен возвращать желаемые результаты. Заранее благодарим за любые советы!

Не могли бы вы предоставить код вашего реагирующего компонента?

Alex 13.04.2018 06:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
1
781
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Попробуй это

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

Убедитесь, что оба ваших массива имеют одинаковый порядок на основе 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);
    }
}
Ответ принят как подходящий

Short clean version

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

Примечание. Чтобы вы знали, что это вложенный цикл. Где map - это петля, проходящая через доску лидеров, а find - это петля, проходящая через плееры. Временная сложность равна О (н * м), где ппg> - общее количество пользователей, а м - длина доски лидерства.

Though if the total number of users isn't huge it shouldn't matter and as long as the code looks clean and understandable that would always be better (:

Если у вас есть количество пользователей ОГРОМНЫЙ, и вы хотите иметь наибольшее количество кода эффективный. Что вам следует сделать, так это сохранить свой playerInfo в карте / объекте, где ключом является playerId, а значением - playerURL. Таким образом, ему нужно всего лишь один раз пройтись по вашим объектам и получить О (1) для фотографий игроков.

Efficient Version

const playerMap = {};

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

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

Временная сложность этого составляет не более На), где ппg> - количество игроков.

Ваше первое решение дает ошибку в JSFiddle. Не могли бы вы проверить код?

Yash Thakur 13.04.2018 07:56

Ой! Спасибо! В основном я пытался сделать псевдокод и не видел JSFiddle

Kenneth Truong 13.04.2018 08:03

Это сработало для меня идеально. Я ценю объяснение.

maison.m 16.04.2018 01:42

Я думаю, что это самое короткое решение по сравнению с другими ответами:

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

Другие вопросы по теме