RxJava에서 플랫 맵과 스위치 맵의 차이점은 무엇입니까?


149

switchmap 의 rxjava doc 정의는 다소 모호하며 flatmap 과 동일한 페이지에 링크됩니다 . 두 연산자의 차이점은 무엇입니까?


1
그것에 대해 flatmap과 동일한 페이지에 링크됩니다 . 정말 사실입니다. 그러나 언어 별 정보 섹션으로 스크롤하여 흥미로운 연산자를 엽니 다. 나는 이것이 TOC에서 자동으로 수행되어야한다고 생각하지만 ... 또한 javadoc 에서 동일한 그림을 볼 수 있습니다 .
Ruslan Stelmachenko

답변:


180

설명서에 따르면 ( http://reactivex.io/documentation/operators/flatmap.html )

switchMap등이다 flatMap, 그러나 새로운 이벤트가 소스 관찰에서 방출 될 때까지 그것은 단지 새로운 관찰에서 항목을 방출합니다.

대리석 다이어그램이 잘 보여줍니다. 다이어그램의 차이점을 확인하십시오.

에서는 switchMap원래 발광 ( 녹색 대리석 ) 번째 발광하지 않는 매핑 발광 ( 녹색 정사각형을 제 사람), 본래 발광 ( 청색 대리석 ) 및 이미 시작된 최초 출사있다 매핑 발광 ( 청색 다이아몬드 ). 다시 말해, 두 개의 매핑 된 녹색 배출 중 첫 번째 만이 발생합니다. 파란색 다이아몬드가 이길 때 녹색 사각형이 방출되지 않습니다.

에서 flatMap"매끄럽지 않은"경우에도 모든 매핑 된 결과가 출력됩니다. 다시 말해, 매핑 된 녹색 방출 의 첫 번째 두 번째가 모두 발생합니다.- 녹색 사각형 이 방출되었을 것입니다 (일관된 맵 기능을 사용하는 경우; 그렇지 않은 경우 두 번째 녹색 다이아몬드가 방출 된 후에도 방출 됨) 최초의 블루 다이아몬드)

switchMap switchMap에서 원래의 관측 가능 물체가 새로운 것을 방출하면 이전의 배출물은 더 이상 매핑 된 관측 가능 물체를 생성하지 않습니다.  오래된 결과를 피하는 효과적인 방법입니다

flatMap

switchMap에서 원래의 관측 가능 물체가 새로운 것을 방출하면 이전의 배출물은 더 이상 매핑 된 관측 가능 물체를 생성하지 않습니다.  이것은 오래된 결과를 방지하는 효과적인 방법입니다


4
감사합니다. 다이어그램이 매우 유용합니다. switchMap이 사용되는 실제 예를 알고 있습니까?
Julian Go

1
@JulianGo 여기에 예제가 있습니다 : github.com/samuelgruetter/rx-playground/blob/master/… 사용 .map(func).switch하지만 .switchMap(func).
Samuel Gruetter

2
누군가 여전히 switchMap의 실제 예가 필요한 경우이 링크 링크를 따라 가면 flatMap 대신 swicthMap을 사용하는시기를 이해할 수 있습니다.
hermannovich

2
RxJs5를 사용하여 Ben Lesh의 SwitchMap을 사용하는 예를 보려면 25-26 분을 참조하십시오. youtube.com/watch?v=3LKMwkuK0ZE 나를 위해 flatmap은 이미 이해되었습니다 ...
arcseldon

7
대리석 다이어그램이 잘 보여? 뭐? 스위치 맵을 이미 이해하고 있다고 생각합니다.
Helzgate

166

"즉석 검색"을 구현할 때 (예 : 사용자가 텍스트 상자에 입력 할 때) 각 키 입력시 거의 실시간으로 결과가 표시됩니다. 해결책은 다음과 같습니다.

  1. PublishSubject of String과 같은 주제가 있습니다.
  2. 텍스트 상자 변경 콜백에서 .onNext (text)를 호출하십시오.
  3. 서버 쿼리 속도를 제한하기 위해 .debounce 필터 적용
  4. .switchMap을 적용하여 서버 쿼리 수행-검색어를 가져 와서 Observable of SearchResponse를 반환
  5. SearchResponse를 소비하고 UI를 업데이트하는 메소드로 .subscribe를 적용하십시오.

flatMap을 사용하면 검색 응답의 순서가 잘못되어 검색 결과가 오래 될 수 있습니다. 이 문제를 해결하려면 새로운 관측기가 제공되면 이전 관측 가능 항목을 구독 취소 할 수 있으므로 switchMap을 사용해야합니다.

따라서 요약하면 타이밍에 관계없이 모든 결과가 중요 할 때는 flatMap을 사용해야하고 마지막 관찰 가능한 결과의 결과 만있을 때 switchMap을 사용해야합니다.



95

아니 flatMap 토론은 비교하고 대조없이 완료 switchMap, concatMap하고 concatMapEager.

이러한 모든 방법 Func1은 스트림을 Observables 로 변환 한 다음 방출됩니다. 그 차이는 반환 된 Observable들이 구독 및 탈퇴 될 때, 그리고 그러한들의 방출이 해당 운영자에 Observable의해 방출되는지의 여부 ____Map이다.

  • flatMapObservable가능한 한 많은 방출을 구독 합니다. (이것은 플랫폼에 의존하는 숫자입니다. 예를 들어 안드로이드의 숫자는 적습니다) 주문이 중요하지 않고 최대한 빨리 방출을 원할 때 이것을 사용하십시오.
  • concatMap첫 번째 Observable구독을 구독 Observable하고 이전 구독 이 완료되면 다음 구독 만 구독합니다 . 주문이 중요하고 자원을 절약하려는 경우에 사용하십시오. 가장 좋은 예는 먼저 캐시를 확인하여 네트워크 호출을 연기하는 것입니다. 그는 일반적으로 다음에 할 수 .first()또는 .takeFirst()불필요한 일을 방지 할 수 있습니다.

    http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

  • concatMapEager거의 동일하게 작동하지만 가능한 한 많은 플랫폼에 가입하지만 이전 Observable이 완료된 후에 만 방출 됩니다. 수행해야하는 많은 병렬 처리가 있지만 flatMap과 달리 원래 순서를 유지하려는 경우에 적합합니다.

  • switchMap마지막 Observable으로 발생한 구독을 구독하고 이전 Observable의 모든 구독을 취소 합니다. 검색 제안과 같은 경우에 적합합니다. 일단 사용자가 검색 쿼리를 변경하면 이전 요청은 더 이상 관심 대상이 아니므로 구독이 취소되며 올바르게 작동하는 Api 엔드 포인트는 네트워크 요청을 취소합니다.

다른 스레드 Observable가 아닌을 반환 subscribeOn하면 위의 모든 메소드가 거의 동일하게 작동 할 수 있습니다. 중첩 된 Observable스레드가 자체 스레드에서 작동 하도록 허용하면 흥미롭고 유용한 동작이 나타납니다 . 그럼 당신은 병렬 처리에서 혜택을 많이받을 얻을 수 있고, 지능적으로 구독 취소 또는에서 가입하지 Observable관심을하지 않는 S Subscriber

  • amb또한 관심이있을 수 있습니다. Observables 개가 주어지면 처음 방출하는 것과 동일한 항목을 Observable방출합니다. 동일한 것을 반환 할 수 있고 성능을 원할 여러 소스가있는 경우 유용 할 수 있습니다. 예를 들어 정렬을 amb사용하면 병합 정렬을 사용하여 빠른 정렬을 수행하고 더 빠른 것을 사용할 수 있습니다.

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- switchMap vs flatMap내가 전에 만난 모든 설명은 이 중요한 측면을 놓쳤습니다. 이제 모든 것이 더 명확합니다. 감사합니다.
Andy Res

55

switchMap는 한 번 불렀다 flatMapLatest RxJS 4.

기본적으로 최신 Observable 의 이벤트를 전달 하고 이전 이벤트의 구독을 취소합니다.


@EpicPandaForce CombineLatest와 일치하지 않지만 소스 관찰 가능 항목이 방출 될 때마다 (한 번만 방출되지는 않음) 최신 값을 방출합니다.
Michael Fry

2
부분적으로 이것이 switchMap이라고하는 이유는 o.map (...). switch ()를 사용하여이 연산자를 직접 구현할 수 있기 때문입니다. 그러나 나는 그것이 혀를 그렇게 쉽게 굴리지 않는 것처럼 보이는 mapSwitch라고 상상할 것입니다.
Niall Connaughton

7

Map, FlatMap, ConcatMapSwitchMap 은 함수가 적용하거나 Observable이 생성 한 데이터를 수정합니다.

  • 은 소스 Observable에서 방출 된 각 항목을 수정하고 수정 된 항목을 방출합니다.

  • FlatMap, SwitchMapConcatMap 은 또한 방출 된 각 항목에 함수를 적용하지만 수정 된 항목을 반환하는 대신 데이터를 다시 방출 할 수있는 Observable 자체를 반환합니다.

  • FlatMapConcatMap 작업은 거의 동일합니다. 여러 Observable에서 방출 한 항목을 병합하고 단일 Observable을 반환합니다.

  • FlatMapConcatMap 의 차이점 은 항목이 방출되는 순서입니다.
  • FlatMap 은 방출하는 동안 항목을 인터리브 할 수 있습니다. 즉 방출 된 항목 순서가 유지되지 않습니다.
  • ConcatMap 은 항목의 순서를 유지합니다. 그러나 ConcatMap의 주요 단점은 각 Observable이 작업을 완료 할 때까지 기다려야하므로 비동기식이 유지되지 않는다는 것입니다.
  • SwitchMapFlatMapConcatMap 과 약간 다릅니다 . SwitchMap 은 새 항목의 방출이 시작될 때마다 이전 소스 Observable의 구독을 취소하므로 항상 현재 Observable에서 항목을 방출합니다.

1

예제 코드를 찾고 있다면

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

https://github.com/politrons/reactive에서 더 많은 예제를 볼 수 있습니다.


4
그러나 flatMap과 구별되는 switchMap의 주요 기능을 놓치게됩니다. 가장 최근의 관찰 가능한 사항 만, 이전의 것을 구독 취소하면됩니다.
Artem Novikov

3
당신이 교체 할 때이 예에서 switchMapflatMap정확히 같은 작동합니다.
Piotr Wittchen

1

다음은 하나 이상의 101 줄 길이의 입니다. 그것은 나를 위해 일을 설명합니다.

말한 것처럼 : 그것은 마지막으로 관찰 할 수있는 것 (당신이 원한다면 가장 느린 것)을 얻고 나머지는 무시합니다.

결과적으로 :

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

A가 무시 된 것을 볼 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.