본문 바로가기

Rx

RxKotlin- Part 8-1. 변환 연산자 : map(), flatMap(), reduce()

728x90

map()

map() 함수는 입력값을 어떤 함수에 넣어서 원하는 값으로 변환하는 함수입니다.

 

String을 String, Integer, 다른 객체 등으로 변환할 수 있습니다.

 

map() 함수의 원형을 살펴보겠습니다.

@CheckReturnValue    //반환값을 확인하다는 의미입니다.
@SchedulerSupport(value="none")    //스케줄러를 지원하지 않는다는 의미로 현재 스레드에서 실행합니다.
public final <R> OBservable<R> map(Function<? super T,? extends R> mapper)

위에서 볼 수 있는 map() 함수의 인자인 Function<? super T,? extends R> mapper은 제네릭 함수형 인터페이스 중 하나입니다. 

 

RxJava의 제네릭 함수형 인터페이스

인터페이스 이름 포함 메소드  설명 
Predicate<T> boolean test(T t)  t 값을 받아서 참이나 거짓을 반환합니다.
Consumer<T> void accept(T t)  t 값을  받아서 처리합니다. 반환값은 없습 니다.
Function<T,R>  R apply(T t)   t 값을 받아서 결과를 반환합니다.

 

Function 인터페이스는 제네릭 타입 T를 인자로 받고 제네릭타입 R을 반환합니다. 

import io.reactivex.Observable
import io.reactivex.functions.Function

fun main(){
    val numList = arrayOf(0, 1, 2)
    val getData = Function<Int,Boolean> { num -> num.toBoolean() }

    val source = Observable.fromArray(*numList).map(getData)
    source.subscribe(
        { println("Received $it") },
        { println("Error : ${it.message}") },
        { println("Complete") }
    )

    source.subscribe { x: Boolean? -> println(x) }
}

private fun Int.toBoolean(): Boolean? {
    when(this){
        0 -> return true
        1 -> return true
        else -> return false
    }
}

실행결과 : 

Received true
Received true
Received false
Complete
true
true
false

 

flatMap()

flatMap() 함수는 map() 함수를 발전시킨 함수로, 위에서 공부했던 map()은 입력 값을 어떤 함수에 넣어서 변환할 수 있는 일대일 함수지만, flatMap() 함수는 일대일 또는 일대다의 Observable 함2수입니다. 

import io.reactivex.Observable
import io.reactivex.functions.Function

fun main(){
    val getData1 = Function<Int, Observable<String>> { num ->
        Observable.create {
            for (i in 0 until 3){
                it.onNext("${num + i}!!")
            }
            it.onComplete()
        }

    }

    val getData2 =
        Function<Int, Observable<String>> { ball: Int ->
            Observable.just("$ball !!", "$ball !!")
        }

    val numbers = arrayOf(1, 2, 3)
    val observable1 = Observable.fromArray(*numbers).flatMap(getData1)
    val observable2 = Observable.fromArray(*numbers).flatMap(getData2)

    observable1.subscribe(System.out::println)
    observable2.subscribe(System.out::println)
}

실행결과 : 

1!!
2!!
3!!
2!!
3!!
4!!
3!!
4!!
5!!
1 !!
1 !!
2 !!
2 !!
3 !!
3 !!

 

Observable<Int> 타입인 observable1과 observable2가 numbers 배열값을 가져와 getData1와 getData2 함수를 활용해 flatMap() 함수를 호출합니다.

함수형 프로그래밍에서는 함수가 입력값, 출력값이 될 수 있고 함수가 함수를 반환할 수도 있습니다.

 

Function 인터페이스 사용없이 람다표현식을 이용한 예제도 해보겠습니다.

import io.reactivex.Observable
import io.reactivex.ObservableEmitter

fun main() {
    val numbers = arrayOf(1, 2, 3)

    val observable1 = Observable.fromArray(*numbers)
        .flatMap { number ->
            Observable.just("$number !!", "$number !!")
        }

    val observable2 = Observable.fromArray(*numbers)
        .flatMap { number ->
            Observable.create { it : ObservableEmitter<String> ->
                for (i in 0 until 3) {
                    it.onNext("${number + i}!!")
                }
                it.onComplete()
            }
        }

    observable1.subscribe{ x: String -> println(x) }
    observable2.subscribe(System.out::println)
}


실행결과 : 

1 !!
1 !!
2 !!
2 !!
3 !!
3 !!
1!!
2!!
3!!
2!!
3!!
4!!
3!!
4!!
5!!

Process finished with exit code 0

 

RxJava에서 여러 개의 데이터를 발행하는 방법은 Observable 밖에 없다고 합니다.

 

reduce()

reduce() 함수는 상황에 따라 발행된 데이터를 취합하여 어떤 결과를 만들고자 할 때 사용합니다. 들어오는 데이터를 1개씩 모아서 최종 결과를 만들 수 있습니다.

 

fun main() {
    val arr = arrayOf(1, 2, 3, 4, 5)
    val sumData = BiFunction { data1: Int, data2: Int -> data1 + data2 }
    val ob = Observable.fromArray(*arr)
        .reduce(sumData)

    ob.subscribe(System.out::println)
}

/*
fun main() {
    val arr = arrayOf(1, 2, 3, 4, 5)
    val ob = Observable.fromArray(*arr)
        .reduce { data1, data2 ->
            data1 + data2
        }

    ob.subscribe(System.out::println)
}
*/

실행결과 : 

15