【问题标题】:How to filter a object list inside of a object list by name property in Kotlin如何在 Kotlin 中按名称属性过滤对象列表中的对象列表
【发布时间】:2020-01-09 08:47:07
【问题描述】:

我正在尝试完成一项被证明很困难的任务。如何实现在 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 与具有特定 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()) } }

给出这个错误:

【问题讨论】:

  • 您自己是如何尝试的?你能告诉我们发生的代码和错误信息吗?
  • 您是从某个地方获取列表并想要过滤它吗?
  • 是的,我试过了。我已经更新了问题
  • 我从后面拿到名单

标签: android kotlin


【解决方案1】:

在过滤时创建新的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 表示我们正在创建一个新列表,其中仅包含非空的 lambda 结果。在 lambda 中,我们要么为新的过滤列表创建 CategoryModel,要么在它没有任何符合所需条件的项目时返回 null 以跳过它。

with 语句中,我们创建一个新的可接受 CollectionModel 过滤列表,如果它不为空,我们将其传递给源 CategoryModel 的新副本。

【讨论】:

    【解决方案2】:

    这感觉有点骇人听闻,因为以下代码使用 CollectionModel 的过滤列表创建了 CategoryModel 的新对象,但它似乎工作。它返回一个MutableList&lt;CategoryModel&gt; 因为

    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&lt;CategoryModel&gt; 的以下扩展功能可能就足够了,虽然感觉不完美:

    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)]
    

    这意味着在collections 中只剩下与CollectionModels 匹配的CategoryModels,并且只剩下那些,所有其他的都已被删除。

    【讨论】:

    • 我在 collectionModel 中得到不包含 textToSearch 的元素.....
    • 嗯...真的吗?然后将isNotEmpty()切换为isEmpty()再试一次,请...
    • 用 isEmpty() 我得到所有元素,除非是正确的项目
    • @S.P.是的,我期待... isNotEmpty() 的原始逻辑应该可以工作。如果不是,那肯定有不同的问题。请在您的问题中添加一些示例数据。
    • 对象模型不完全是这样。试试这个: var collection1 = CollectionModel(1, "xxxxx", "Rice") var collection2 = CollectionModel(1, "xxxxx", "Pasta") var collectionListtoAdd = arrayListOf(collection1, collection2) var collectionToSearch = CategoryModel(collectionListtoAdd, 1,“米饭和意大利面”)
    【解决方案3】:

    你可以试试这个:

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

    【讨论】:

    • 我已经尝试过,但在 .reduce 中出现错误。看看我的更新问题,我附上了错误的屏幕截图
    • 只指定泛型类型collection.reduce&lt;List&lt;CollectionModel&gt;, List&lt;CollectionModel&gt;&gt; { ... }
    • 我无法正确输入泛型类型,抱歉
    • 私有变量集合:List = emptyList()
    • 这个逻辑呢? collection.filter { it.collections.any { it.name.contains(textToSearch.capitalize()) } }
    【解决方案4】:

    一个简单的方法是使用嵌套过滤器

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

    【讨论】:

      猜你喜欢
      • 2020-12-14
      • 2020-07-01
      • 2015-11-28
      • 2010-09-25
      • 1970-01-01
      • 2018-10-19
      • 1970-01-01
      • 2019-06-08
      • 1970-01-01
      相关资源
      最近更新 更多