groupBy в ключ и значения - PullRequest
       36

groupBy в ключ и значения

0 голосов
/ 05 апреля 2019

Вопросы полужирный ниже. Учитывая, что это мой компонент HTML UI:

<mat-tab label="Beginners">
  <courses-card-list [courses]="coursesBeginners$ | async">
  </courses-card-list>
</mat-tab>

<mat-tab label="Advanced">
  <courses-card-list [courses]="coursesAdvanced$ | async">
  </courses-card-list>
</mat-tab>

У меня есть курсы $ observable, которые мне нужно отфильтровать по нескольким наблюдаемым в зависимости от категории каждого курса. Для краткости я ограничу пример двумя категориями. Я использовал этот фрагмент в своем компоненте ts в приложении Angular 7:

this.beginnersCourses$ = this.courses$.pipe(
  map(courses => courses.filter(
    course => course.categories.includes("BEGINNER"))));

this.advancedCourses$ = this.courses$.pipe(
  map(courses => courses.filter(
    course => course.categories.includes("ADVANCED"))));

к этому:

let courses0: Course[] = [];
let courses1: Course[] = [];
courses$
  .pipe(
    map(courses => {
      courses.forEach(course => {
        if (course.categories.includes('BEGINNER')) {
          courses0.push(course);
        } else if (course.categories.includes('ADVANCED')) {
          courses1.push(course);
        }
      });
    }),
  )
  .subscribe(() => {
    this.coursesBeginners$ = of(courses0);
    this.coursesAdvanced$ = of(courses1);
  });

Хотя вторая версия - больше кода, она более эффективна, потому что мы выполняем итерацию только один раз в коллекции курсов, а не столько раз, сколько есть категории. Кстати, можно ли сделать его еще короче?

Теперь, , я хотел бы написать еще более эффективный код, используя groupBy, как указано здесь во втором примере на сайте learnrxjs, но у меня есть проблема с отображением моей проблемы в простой пример, показанный в примере - моя ценность - это целый объект курса, а не просто свойство. Я также попробовал подход, показанный здесь в документации по rxjs, но я не прошёл мимо функции reduce без ошибок компиляции.

Я также понимаю, что может быть трудно разделить на основе метода includes, в этом случае даже выбор значения course.categories[0] будет удовлетворительным, если нет другого способа.

Спасибо!

1 Ответ

1 голос
/ 05 апреля 2019

Вы можете определить имеющиеся у вас трудности статически, а затем использовать их для циклического прохождения курсов, чтобы сгруппировать их по типу сложности, и затем вы можете также использовать их в своем шаблоне для создания пользовательского интерфейса для каждой сложности, используя ngForOf.

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

import { of } from 'rxjs';
import { map, reduce, concatAll } from 'rxjs/operators';

enum CourseDifficulties {
  BEGINNER = 'BEGINNER',
  ADVANCED = 'ADVANCED',
  EXPERT = 'EXPERT',
};

const COURSES_DATA = [
  { name: 'Course 1', categories: [CourseDifficulties.BEGINNER, CourseDifficulties.ADVANCED] },
  { name: 'Course 2', categories: [CourseDifficulties.ADVANCED] },
  { name: 'Course 3', categories: [CourseDifficulties.EXPERT] },
  { name: 'Course 4', categories: [CourseDifficulties.EXPERT] },
  { name: 'Course 5', categories: [CourseDifficulties.ADVANCED] },
];

const AVAILABLE_DIFFICULTIES = [
  { name: 'Beginner', type: CourseDifficulties.BEGINNER },
  { name: 'Advanced', type: CourseDifficulties.ADVANCED },
  { name: 'Expert', type: CourseDifficulties.EXPERT },
];

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  public readonly difficulties = AVAILABLE_DIFFICULTIES;
  public readonly coursesByDifficulty$ = this.getCourses();



  public getCourses()
  {
    return of(COURSES_DATA).pipe(
      map(courses => courses.reduce((result, course) =>
      {
        this.difficulties.forEach(({ type }) =>
        {
          if(course.categories.indexOf(type) > -1)
          {
            result[type] = (result[type] || []).concat(course);
          }
        });
        return result;
      }, {}))
    );
  }
}

DEMO

...