Как отфильтровать список объектов внутри списка объектов по свойству name в Kotlin - PullRequest
0 голосов
/ 09 января 2020

Я пытаюсь выполнить задачу, которая оказывается трудной. Как мне достичь цели, чтобы отфильтровать список в Kotlin? Я искал здесь с фильтром и картой, но было невозможно сделать это.

У меня есть этот класс данных.

data class CategoryModel(
    val collections: List<CollectionModel>,
    val id: Int,
    val name: String
)

data class CollectionModel(
    val id: Int,
    val image: String,
    val name: String
)

Что я хочу сделать, это получить список CategoryModel, которые имеют только collectionModel, которые соответствуют подстроке с указанным c collectionModel.name.

Это код, который я пробовал, но если collectionModel имеет два элемента, я получаю оба, и я хочу только элемент, который содержит подстрока:

collection.forEachIndexed { index, element ->
    for (collectionModel in collection[index].collections) {
        if (collectionModel.name.contains(textToSearch.capitalize())) {
             collectionSearch.add(collection[index])
        }
    }
}
return collectionSearch

ОБНОВЛЕНИЕ 1

collection.reduce{ acc, list ->  list.collections.filter { it.name.contains(textToSearch.capitalize()) } }

выдать эту ошибку:

![image error

Ответы [ 5 ]

2 голосов
/ 09 января 2020

Самое чистое - создавать новые CategoryModel экземпляры в процессе фильтрации. В любом случае, это хорошие неизменяемые модели.

val criterion = textToSearch.capitalize()
val filtered = collection.mapNotNull { sourceCategory ->
    with (sourceCategory.collections.filter { criterion in it.name }) {
        if (isNotEmpty())
            CategoryModel(this@with, sourceCategory.id, sourceCategory.name)
        else
            null
    }
}

Объяснение:

mapNotNull означает, что мы создаем новый список, содержащий только результаты лямбды, которые не равны нулю. В лямбда-выражении мы либо создаем CategoryModel для нового отфильтрованного списка, либо возвращаем значение null, чтобы пропустить его, когда в нем не было элементов с требуемыми критериями.

В операторе with мы создаем новый отфильтрованный список допустимых CollectionModels и, если он не пустой, мы передаем его новой копии исходного CategoryModel.

2 голосов
/ 09 января 2020

Это выглядит несколько странно, потому что следующий код создает новые объекты CategoryModel, используя отфильтрованный список CollectionModel, но, похоже, работает. Он возвращает MutableList<CategoryModel>, потому что

var collectionSearch: List<CategoryModel> = categoryModelList.filter {
    // check each CategoryModel
    categoryModel -> categoryModel.collections.filter {
        // check if there are CollectionModels with a name containing capitalized textToSearch
        collectionModel -> collectionModel.name.contains(textToSearch.capitalize())
    }.isNotEmpty() // only consider those with a non empty result
}.toList()  // get all the matching CategoryModels as List<CategoryModel>

Вызов этого типа fun main, подобного этому

fun main() {
    // minimal data sample
    var categoryModelList: List<CategoryModel> = listOf(
        CategoryModel(listOf(CollectionModel(1, "collMod A", "nameA")), 1, "catMod A"),
        CategoryModel(listOf(CollectionModel(1, "collMod B", "nameB")), 2, "catMod B")
    );

    // sample text to be found
    val textToSearch: String = "b";

    // here it is
    var collectionSearch: List<CategoryModel> = categoryModelList.filter {
        categoryModel -> categoryModel.collections.filter {
            collectionModel -> collectionModel.name.contains(textToSearch.capitalize())
        }.isNotEmpty()
    }.toList()

    println(collectionSearch)
}

, приводит к следующему выводу:

[CategoryModel(collections=[CollectionModel(id=1, image=collMod B, name=nameB)], id=2, name=catMod B)]

, который Появляется желаемым.

РЕДАКТИРОВАТЬ

После прояснения требований может быть достаточной следующая функция расширения List<CategoryModel>, хотя она кажется не идеальной:

fun List<CategoryModel>.getModified(condition: String): List<CategoryModel> {
    var result: MutableList<CategoryModel> = mutableListOf();

    this.forEach { categoryModel ->
        // get a list of matching CollectionModels
        val cols = categoryModel.collections.filter { collectionModel ->
            collectionModel.name.contains(condition.capitalize())
        }
        // if the list is not empty
        if (cols.isNotEmpty()) {
            /*
             * add a new item to the result using the filtered collections
             * and the other (unmodified) attributes
             */
            result.add(CategoryModel(cols, categoryModel.id, categoryModel.name))
        }
    }

    return result
}

Когда Я называю это так:

fun main() {
    // minimal data sample
    var categoryModelList: List<CategoryModel> = listOf(
        CategoryModel(mutableListOf(CollectionModel(1, "collMod A", "nameA"),
                            CollectionModel(2, "collMod B", "nameB")
                            ), 1, "catMod 1"),
        CategoryModel(mutableListOf(CollectionModel(3, "collMod B", "nameB")), 2, "catMod 2"),
        CategoryModel(mutableListOf(CollectionModel(4, "collMod BB", "nameBB"),
                            CollectionModel(5, "collMod C", "nameC")
                            ), 3, "catMod 3"),
        CategoryModel(mutableListOf(CollectionModel(6, "collMod A", "nameA"),
                            CollectionModel(7, "collMod D", "nameD")
                            ), 4, "catMod 4")
    );

    // sample text to be found
    val textToSearch: String = "b";
    // print the source
    println(categoryModelList)
    // and the modified list in order to compare them
    println(categoryModelList.getModified(textToSearch))
}

вывод выглядит как желаемый:

[CategoryModel(collections=[CollectionModel(id=1, image=collMod A, name=nameA), CollectionModel(id=2, image=collMod B, name=nameB)], id=1, name=catMod 1), CategoryModel(collections=[CollectionModel(id=3, image=collMod B, name=nameB)], id=2, name=catMod 2), CategoryModel(collections=[CollectionModel(id=4, image=collMod BB, name=nameBB), CollectionModel(id=5, image=collMod C, name=nameC)], id=2, name=catMod 3), CategoryModel(collections=[CollectionModel(id=6, image=collMod A, name=nameA), CollectionModel(id=7, image=collMod D, name=nameD)], id=3, name=catMod 4)]
[CategoryModel(collections=[CollectionModel(id=2, image=collMod B, name=nameB)], id=1, name=catMod 1), CategoryModel(collections=[CollectionModel(id=3, image=collMod B, name=nameB)], id=2, name=catMod 2), CategoryModel(collections=[CollectionModel(id=4, image=collMod BB, name=nameBB)], id=2, name=catMod 3)]

, что означает, что осталось только CategoryModel с соответствующими CollectionModel с collections и там остались только те, все остальные удалены.

0 голосов
/ 09 января 2020

Простой подход - использование вложенного фильтра

  val list = mutableListOf<CategoryModel>()
    val filteredlist = list.filter {
        val sublist = it.collections.filter {
            it.name == "your text here..."
        }
        return@filter it.collections == sublist

    }
0 голосов
/ 09 января 2020

вы можете использовать фильтр, содержит и любые подобные функции

val myCategories = mutableListOf<CategoryModel>()
val searchCollection = mutableListOf<CollectionModel>()

collection.forEach { categoryModel ->
        if (categoryModel.collections.any { it.name == sommeText }) {
            myCategories.add(categoryModel)
            searchCollection.addAll(categoryModel.collections.filter {
                it.name.contains(sommeText, true)
            })
        }
    }

myCategories будет содержать все модели CategoryModel, которым одно из названий моделей его коллекции соответствует подстроку, а коллекция поиска содержит все модели collectionModels, которые соответствуют подстроке.

0 голосов
/ 09 января 2020

Вы можете попробовать это:

collection.reduce { acc, list ->  list.filter { it.name.contains(textToSearch.capitalize()) } }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...