본문 바로가기
Rx

리액티브연산자[변환 연산자]-13(groupBy, scan)

by 봄석 2018. 12. 26.

본 내용은 필자가 학습한 내용을 정리하는 내용입니다.

대부분 의 내용이 아래 책의 내용이므로 원서를 구매해서 직접보시는걸 추천드립니다!

RxJava 프로그래밍 리액티브 프로그래밍 기초부터 RxAndroid까지 한 번에

유동환 , 박정준 지음 | 한빛미디어 | 2017년 09월 04일 출간

http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788968488658&orderClick=LAV&Kc=


저자님의 블로그

https://brunch.co.kr/@yudong#info




리액티브 연산자(함수) 분류 - 카테고리

연산자 종류 

연산자 함수 

  생성 연산자 


 just(), fromXXX(), create(), interval(), ragne(), timer(),   intervalRange(), defer(), repeat() 


  변환 연산자


 map(),flatMap(), concatMap(), switchMap() , groupBy(),

 scan(), buffer(), window()


  필터 연산자


 filter(), take(), skip(), distinct()


  결합 연산자

 

 zip(), combineLatest(), merge(), concat()

 

  조건 연산자


 amb(), takeUtil(), skipUtil(), all()

 

  에러 처리 연산자 


 onErrorReturn(), onErrorResumeNext(), retry(), retryUntil()


  기타 연산자 

 

 subscribe(), subscribeOn(), observeOn(), reduce(), count()

 




변환 연산자- groupBy()함수

groupBy() 함수는 어떤 기준(KeySelector 인자)으로 단일 Observable을 여러개로 이루어진 Observable 그룹(GruopObservable)로 만듭니다.


groupBy() 함수의 마블다이어그램

출처 - http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html


우선 어떤 기준으로 Observable 각각을 여러개 Observable로 구분한다고 생각하면됩니다.


groupBy()함수의 활용 예

String[] objs={"6","4","2-T","2","6-T","4-T"};
Observable<GroupedObservable<String,String>> source=
Observable.fromArray(objs).groupBy(Shape::getShape);
        
source.subscribe(obj->{
        obj.subscribe(val->System.out.println("GROUP:"+obj.getKey()+"\t Value:"+val));
});

Colored by Color Scripter


Shape 클래스의 getShape

public static String getShape(String obj) {
        if (obj == null || obj.equals("")) return NO_SHAPE;        
        if (obj.endsWith("-H")) return HEXAGON;
        if (obj.endsWith("-O")) return OCTAGON;
        if (obj.endsWith("-R")) return RECTANGLE;
        if (obj.endsWith("-T")) return TRIANGLE;
        if (obj.endsWith("<>")) return DIAMOND;
        if (obj.endsWith("-P")) return PENTAGON;
        if (obj.endsWith("-S")) return STAR;
        return "BALL";

    }   


실행결과

GROUP:BALL     Value:6
GROUP:BALL     Value:4
GROUP:TRIANGLE     Value:2-T
GROUP:BALL Value:2
GROUP:TRIANGLE     Value:6-T

GROUP:TRIANGLE     Value:4-T



GroupObservable 클래스는 Observable 과 동일하지만 getKey()라는 메소드를 통해 구분된 그룹을 알수있게 해줍니다. source는 objs[] 배열에서 입력 데이터를 가져옵니다. 그룹을 구별하는 방법은 Shape.getShape()라는 정적 메소드를 호출한 것입니다.


한편 source.subscribe()에 전달하는 obj는 GroupedObservable 객체입니다. 그룹별로 1개씩 생성되므로 생성된 obj별로 subscribe()함수를 한번 더 호출해야 합니다.

val은 그룹안에서 각 Observable이 발행한 데이터를 의미합니다.


만약 특정 그룹만 처리하고 싶다면 filter()함수를 추가하면 됩니다

String[] objs={"6","4","2-T","2","6-T","4-T"};
Observable<GroupedObservable<String,String>> source=
Observable.fromArray(objs).groupBy(Shape::getShape);
        
source.subscribe(obj->{
obj.filter(var->obj.getKey().equals("BALL")).
    subscribe(val->System.out.println("GROUP:"+obj.getKey()+"\t Value:"+val));
});

Colored 



실행결과

GROUP:BALL     Value:6
GROUP:BALL     Value:4

GROUP:BALL     Value:2





map(), flatMap(), groupBy() 함수의 동작 비교하기

map() 함수는 1개의 데이터를 다른 값이나 다른 타입으로 변환해 줍니다.

flatMap() 함수는 1개의 값을 받아서 여러개의 데이터(Observable)로 확장해줍니다

groupBy() 함수는 값들을 받아서 어떤 기준에 맞는 새로운 Observable을 다수를 생성합니다.



변환 연산자- scan()함수

scan() 함수는 3장에서 배운 reduce() 함수와 비슷합니다. reduce() 함수는 Observable에서 모든 데이터가 입력된 후 그것을 종합하여 마지막 1개의 데이터만을 구독자에게 발행했습니다.

반면 scan() 함수는 실행할 때마다 입력값에 맞는 중간 결과 및 최종 결과를 구독자에게 발행합니다.


scan() 함수의 마블다이어그램

출처 - http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html


reduce() 함수를 scan() 함수로 변경해본 예

String[] balls={"1","3","5"};
Observable<String> source= Observable.fromArray(balls).scan((ball1,ball2)->ball2+"("+ball1+")");

source.subscribe(Log::i);


실행결과

main | value = 1
main | value = 3(1)

main | value = 5(3(1))


앞에서 실습했던 reduce()와 다른점은 크게 두가지 입니다.

첫 번쨰는 source의 타입이 Maybe<String>이 아니라 Observable<String>이라는 것 입니다.

reduce() 함수의 경우 마지막 값이 입력되지 않거나, onComplete 이벤트가 발생하지 않으면 구독자에게 값을 발행하지 않습니다. 최악의 경우에는 값을 전혀 발행하지 않고 종료할 수도 있으므로 Maybe 클래스 타입을 썻습니다. 반면 scan() 함수는 값이 입력될 때마다 구독자에게 값을 발행합니다. 따라서 Maybe가 아니라 Observable 입니다.


두 번째는 결과를 출력하기 위해 중간값마다 Log를 찍을수 있다는 것입니다(어떤스레드에서 실행되는지 표시 포함)



댓글