Rx JS отличный оператор не принимает различные значения из массива объектов - PullRequest
0 голосов
/ 05 апреля 2020

Я использую API изображений, чтобы получить некоторую информацию об изображении, и я хочу создать массив с уникальными именами авторов для каждого возвращаемого изображения. Я использую distinct Rx JS, чтобы попытаться сделать это, но сейчас все объекты возвращаются.

Вот как выглядят данные API:

[
  {
    "id": "117",
    "author": "Daniel Ebersole",
    "width": 1544,
    "height": 1024,
    "url": "https://unsplash.com/photos/Q14J2k8VE3U",
    "download_url": "https://picsum.photos/id/117/1544/1024"
  },
  {
    "id": "118",
    "author": "Rick Waalders",
    "width": 1500,
    "height": 1000,
    "url": "https://unsplash.com/photos/d-Cr8MEW5Uc",
    "download_url": "https://picsum.photos/id/118/1500/1000"
  }
]

Вот часть кода, которую я упростил для облегчения чтения:

export class AppComponent {

  authors; // using an array of strings for this doesn't work when I try to set it from the subscribe()

  ngOnInit() {
    const apiURI = 'https://picsum.photos/v2/list?page=2&limit=100';

    const authors$ = this.http.get(apiURI).pipe(
      distinct((item: Image) => item.author),
      tap(author => console.log(author))
    );

    authors$.subscribe(authors => this.authors = authors);
  }

  constructor(private http: HttpClient) { }
}

export interface Image {
    id: number;
    author: string;
    width: number;
    height: number;
    url: string;
    download_url: string;
}

StackBlitz

Это странно для меня, так как есть еще один StackBlitz Я нашел с примерами, которые по сути делают то же самое с массивом объектов.

Я впервые работаю с оператором distinct, поэтому я уверен, что что-то упустил, но я не смог понять, что это такое. Спасибо.

Ответы [ 4 ]

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

Серьезно, ребята :) distinct() должен работать с потоком, генерирующим множественные значения. Но мы имеем дело с одним значением, полученным из вызова API! Нам не нужен rx js для выполнения синхронного преобразования массива - это просто не подходящий инструмент для этого.

Задача: взять список элементов в качестве входных данных, вернуть список уникальных авторов. Это тривиально, с простым JS кодом или с lodash / underscore.

function getUniqueAuthors(items Item[]): string[] {
  const authors = items.map(item => item.author);
  return [...(new Set(authors).values()];
  // or can do this with lodash: return _.unique(authors);
}

// transform results inside subscribe()
this.http.get(apiURI).subscribe(items => {
  this.authors = getUniqueAuthors(items)
})

// or can get fancy and perform mapping inside the pipe:
this.http.get(apiURI)
  .pipe(map(getUniqueAuthors))
  .subscribe(authors => {
    this.authors = authors
  })

Я смиренно считаю, что это более простой подход, чем преобразование массива в поток, генерирующий отдельные элементы, а затем сбор их обратно в массив .

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

Flatten сначала массив, затем применить distinct и собрать.

export class AppComponent {
  authors: string[];

  ngOnInit() {
    const apiURI = 'https://picsum.photos/v2/list?page=2&limit=100';
    const authors$ = this.http.get(apiURI).pipe(
      flatMap(x => x),
      distinct((item: Image) => item.author),
      toArray()  
    );

    authors$.subscribe(authors => console.log(JSON.stringify(authors)));
  }

  constructor(private http: HttpClient) { }
}

// Здесь: https://stackblitz.com/edit/angular-x6cwp5

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

distinct позволит вам указать поле для проверки, само по себе оно не будет отображать объект для возврата только имени автора (или выбранного поля).

Вы можете использовать switchMap для достижения этого:

const authors$ = this.http.get(apiURI).pipe(
      mergeAll(),
      distinct((item: Image) => item.author),
      switchMap((author: any) => of(author.author))
    );

Я обновил ваш стек: https://stackblitz.com/edit/angular-x6cwp5

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

this.http.get выдаст массив значений, а не каждое значение в отдельности. Вот почему отличное не действует здесь. Но вы можете преобразовать массив значений для выдачи каждого значения отдельно с помощью оператора mergeAll

постоянных авторов .author));

...