Поиск в массиве свойства объекта, в котором свойство может быть одинаковым в нескольких объектах - чтобы избежать возврата одного и того же объекта? - PullRequest
1 голос
/ 18 апреля 2020

Я создаю это приложение в Angular, но моя проблема в основном просто JavaScript. У меня есть два объекта, roles и contacts.

contacts состоит из адресов электронной почты и их соответствующего номера «роли».

roles просто отображает номер роли на заголовок.

У меня есть функция getRole(email), которая использует array.find на contacts для соответствующего электронного письма и возвращает номер роли , Затем другой array.find, чтобы сопоставить номер роли с названием роли. У меня есть таблица, отображающая все это.

Проблема в том, что может быть один и тот же адрес электронной почты для нескольких ролей. Использование this.contacts.findIndex(p => p.email === email) просто находит первое соответствующее письмо. Поэтому всем повторным электронным письмам отводится роль первого найденного объекта (поэтому вы увидите, что все test@example.com адреса показывают «первый» в таблице).

Мне удалось решить эту проблему, но я чувствую, что способ, которым я это сделал, не является хорошим решением. По сути, создается копия массива contacts, поиск в скопированном массиве и склеивание любого найденного объекта после его возврата. Однако я чувствую, что есть более чистый и более эффективный способ сделать это, и мне не нравится использовать внешний скопированный массив.

Stackblitz: https://stackblitz.com/edit/angular-ebmcy2

Компонент (жестко закодированные контакты в настоящее время):

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  roles = [
    { role: 1, title: 'first'},
    { role: 2, title: 'second'},
    { role: 3, title: 'third'},
    { role: 4, title: 'fourth'},
    { role: 5, title: 'fifth'},
  ];

  contacts = [
    { email: 'test@example.com', role: 1 },
    { email: 'test@example.com', role: 2 },
    { email: 'test@example.com', role: 3 },
    { email: 'dave@example.com', role: 4 },
    { email: 'test@example.com', role: 5 }
  ]

  tempContacts = this.contacts.concat();

  getRole(email) {
    // MY SOLUTION
    // if (this.tempContacts) {
    //   let contact = this.tempContacts.find(p => p.email === email);
    //   let contactIndex = this.tempContacts.findIndex(p => p.email === email);
    //   this.tempContacts.splice(contactIndex, 1);
    //   return this.roles.find(o => o.role === contact.role).title;
    // }

    let contact = this.contacts.find(p => p.email === email);
    let contactIndex = this.contacts.findIndex(p => p.email === email);
    return this.roles.find(o => o.role === contact.role).title;

  }
}

Шаблон:

<table>
  <tr>
    <th>Email</th>
    <th>Role</th>
  </tr>
  <tr *ngFor="let contact of contacts">
    <td>{{ contact.email }}</td>
    <td>{{ getRole(contact.email) }}</td>
  </tr>
  </table>

Вывод: Снимок экрана

1 Ответ

0 голосов
/ 18 апреля 2020

У вас уже есть роль в массиве contacts, который вы перебираете - getRole фактически получает заголовок . Как насчет изменения имени функции на getTitle и передачи ему role? Номера ролей не повторяются, поэтому это позволяет избежать проблемы дублирования электронной почты.

<td>{{ getTitle(contact.role) }}</td>
getTitle(role) {
  return this.roles.find(item => item.role === role).title;
}

Чтобы уменьшить сложность вычислений с O(n ^ 2) до O(n), создайте роли сопоставления объектов для их заголовки заранее, вместо .find в массиве на каждой итерации:

this.titlesByRole = {};
for (const { role, title } of this.roles) {
  this.titlesByRole[role] = title;
}
<td>{{ titlesByRole[contact.role] }}</td>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...