Как мне написать преобразование более чистым способом - PullRequest
0 голосов
/ 27 мая 2020

У меня есть метод, который принимает список объектов (виджет), который содержит некоторые свойства (заголовок) и вложенный список (компонент). Я хочу объединить список в один список и иметь для него следующий код:

@SuppressLint("CheckResult")
    fun flatten(fatList: Single<List<Widget>>) {
        val flatList: MutableList<IUiData> = mutableListOf()

        fatList.map {
            Observable.fromIterable(it).map { widget ->
                if (widget.header.isNotEmpty()) {
                    flatList.add(ProductHeaderUi(widget.header))
                }
                widget.componentList.map { component ->
                    when (component.type) {
                        TILE_TEXT -> {
                            flatList.add(HeaderUi(component))
                        }
                        TILE_IMAGE -> {
                            flatList.add(ImageTileUi(component))
                        }
                        TILE_FOOTER -> {
                            flatList.add(FooterUi(component))
                        }
                        UNKNOWN -> {
                            //Do Nothing 
                        }
                    }
                }
            }
        }
    }

Я собираюсь вернуть Single of List: Single<MutableList<IUiData>> из этого метода, эта цель может быть выполнена прямо сейчас , но ищу более чистый способ

1 Ответ

2 голосов
/ 27 мая 2020

Вы используете оба Rx's Observable map и Kotlin Iterable map непреднамеренно. Они предназначены для преобразования одного типа в другой, а не для итерации чего-либо.

Вы также вложили ненужный Observable итерируемый объект внутрь самой внешней функции карты.

Вам нужно только сопоставить вывод сингла. Внутри функции map вы повторяете (а не map) исходный список, чтобы извлечь данные, необходимые для MutableList.

Я новичок в Rx и не проверял это, извините о любых синтаксических ошибках.

fun flatten(fatList: Single<List<Widget>>): Single<MutableList<IUData>> = fatList.map { widgetList ->
    val flatList: MutableList<IUiData> = mutableListOf()
    for (widget in widgetList) {
        if (widget.header.isNotEmpty()) {
            flatList.add(ProductHeaderUi(widget.header))
        }
        for (component in widget.componentList) { 
            when (component.type) {
                TILE_TEXT -> flatList.add(HeaderUi(component))
                TILE_IMAGE -> flatList.add(ImageTileUi(component))
                TILE_FOOTER -> flatList.add(FooterUi(component))
                // Else do nothing
            }
        }
    }
    flatList
}

Но, в соответствии с типичным синтаксисом цепочки Rx, я бы сделал это функцией расширения, поэтому мне пришлось бы первую строку, подобную этой. Затем вы можете поместить его прямо в середину цепочки вызовов Rx:

fun Single<List<Widget>>.flatten(): Single<MutableList<IUData>> = map { widgetList ->

Вы также можете сделать это более кратким, функциональным, но менее эффективным способом, используя Kotlin s flatMap :

fun Single<List<Widget>>.flatten(): Single<MutableList<IUData>> = map {
    it.flatMap { widget ->
        listOfNotNull(widget.header.takeIf(Header::isNotEmpty)?.let(::ProductHeaderUi))
        +
        widget.componentList.mapNotNull { component ->            
           when (component.type) {
                TILE_TEXT -> HeaderUi(component)
                TILE_IMAGE -> ImageTileUi(component)
                TILE_FOOTER -> FooterUi(component)
                else -> null
            }
        }.toMutableList()
}

... где Header - это любой тип, который использует widget.header.

...