使用谓词的通用集合过滤
Generic collection filtering using predicates
我遇到了一个关于 kotlin 中集合过滤的棘手问题...
我有一个管理项目列表的基础 class,我希望能够使用关键字过滤列表,因此我使用 Filterable 方法扩展了 class。
我想做的是能够用这个 'base class' 扩展多个 classes,所以过滤器机制对于所有 classes 都是相同的。
这些 class 没有相同的属性...在一个中,必须根据是否在 'name' 中找到关键字进行过滤,而在另一个 class 中过滤是在 'comment' 属性.
上完成的
这里是一些代码:
data class ProductInfo(): {
var _name: String
var name: String
get() = _name
set(value) { _name = value }
}
abstract class BaseFirestoreAdapter<T : BaseFirestoreAdapter.DataInterface, VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>(), Filterable
{
var sourceList: MutableList<ProductInfo> = ArrayList()
...
override fun performFiltering(keyword: CharSequence): FilterResults {
val keywordRegex = keyword.toString().toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.LITERAL))
filteredList = sourceList.filter {
keywordRegex.containsMatchIn(Normalizer.normalize(it.name, Normalizer.Form.NFD).replace("[^\p{ASCII}]".toRegex(RegexOption.IGNORE_CASE), ""))
}
results.values = filteredList.sortedWith(orderComparator)
results.count = filteredList.size
}
...
}
我开发了 'base class' 所以它可以与上面提到的第一个 class 一起工作(过滤是用 'it.name' 完成的)并且它可以工作但是现在我正在尝试制作它是通用的 (T) 与第二个 class (评论)一起使用,我找不到办法做到这一点...
我想我可以传递一个 class 相关的谓词来定义如何在过滤过程中匹配项目,但是由于关键字只在 performFiltering 方法中已知,我无法在这个之外正确地创建谓词方法...
我现在有点没主意了!哈哈
你们有什么想法吗?
UPDATE:按照@Tenfour04 的建议,我尝试将其调整为我的代码,该代码通过一种方法而不是使用构造函数传递过滤谓词,但它不会编译,除非我替换 "ActivyInfo::comments" 与 "ActivyInfo::comments.name" 之类的东西,但随后
我在调试中为 "searchedProperty(it)" 获得的值是 "name",这不是注释值。
代码如下:
评论适配器:
override fun getFilter(): Filter {
super.setFilter(
{ it.state != ProductState.HIDDEN },
{ ActivyInfo::comments },
compareBy<ProductInfo> { it.state }.thenBy(String.CASE_INSENSITIVE_ORDER) { it.name })
return super.getFilter()
}
基础适配器:
lateinit var defaultFilterPredicate : (T) -> Boolean
lateinit var searchedProperty : (T) -> CharSequence
lateinit var orderComparator : Comparator<T>
fun setFilter(defaultPredicate: (T) -> Boolean, property: (T) -> CharSequence, comparator: Comparator<T> ) {
defaultFilterPredicate = defaultPredicate
searchedProperty = property
orderComparator = comparator
}
override fun performFiltering(constraint: CharSequence): FilterResults {
...
filteredList = sourceList.filter {
constraintRegex.containsMatchIn(Normalizer.normalize(searchedProperty(it), Normalizer.Form.NFD).replace("[^\p{ASCII}]".toRegex(RegexOption.IGNORE_CASE), ""))
}
...
}
您可以将 属性 指定为函数的参数传递给构造函数。
abstract class BaseFirestoreAdapter<T : BaseFirestoreAdapter.DataInterface, VH : RecyclerView.ViewHolder>(val filteredProperty: (T) -> CharSequence) : RecyclerView.Adapter<VH>(), Filterable
{
var sourceList: MutableList<T> = ArrayList()
// ...
override fun performFiltering(keyword: CharSequence): FilterResults {
val keywordRegex = keyword.toString().toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.LITERAL))
filteredList = sourceList.filter {
keywordRegex.containsMatchIn(Normalizer.normalize(filteredProperty(it), Normalizer.Form.NFD).replace("[^\p{ASCII}]".toRegex(RegexOption.IGNORE_CASE), ""))
}
results.values = filteredList.sortedWith(orderComparator)
results.count = filteredList.size
}
...
}
我对你的所做的更改是添加构造函数参数 filteredProperty
,将 sourceList
类型更改为 T
,并将 it.name
替换为 filteredProperty(it)
.
所以子类必须调用这个超级构造函数,像这样传递 属性:
data class SomeData(val comments: String)
class SomeDataAdapter: BaseFirestoreAdapter<SomeData>(SomeData::comments) {
//...
}
或者如果你想保持它的通用性:
class SomeDataAdapter(filteredProperty: (T) -> CharSequence): BaseFirestoreAdapter<SomeData>(filteredProperty) //...
我遇到了一个关于 kotlin 中集合过滤的棘手问题...
我有一个管理项目列表的基础 class,我希望能够使用关键字过滤列表,因此我使用 Filterable 方法扩展了 class。
我想做的是能够用这个 'base class' 扩展多个 classes,所以过滤器机制对于所有 classes 都是相同的。
这些 class 没有相同的属性...在一个中,必须根据是否在 'name' 中找到关键字进行过滤,而在另一个 class 中过滤是在 'comment' 属性.
上完成的这里是一些代码:
data class ProductInfo(): {
var _name: String
var name: String
get() = _name
set(value) { _name = value }
}
abstract class BaseFirestoreAdapter<T : BaseFirestoreAdapter.DataInterface, VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>(), Filterable
{
var sourceList: MutableList<ProductInfo> = ArrayList()
...
override fun performFiltering(keyword: CharSequence): FilterResults {
val keywordRegex = keyword.toString().toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.LITERAL))
filteredList = sourceList.filter {
keywordRegex.containsMatchIn(Normalizer.normalize(it.name, Normalizer.Form.NFD).replace("[^\p{ASCII}]".toRegex(RegexOption.IGNORE_CASE), ""))
}
results.values = filteredList.sortedWith(orderComparator)
results.count = filteredList.size
}
...
}
我开发了 'base class' 所以它可以与上面提到的第一个 class 一起工作(过滤是用 'it.name' 完成的)并且它可以工作但是现在我正在尝试制作它是通用的 (T) 与第二个 class (评论)一起使用,我找不到办法做到这一点...
我想我可以传递一个 class 相关的谓词来定义如何在过滤过程中匹配项目,但是由于关键字只在 performFiltering 方法中已知,我无法在这个之外正确地创建谓词方法...
我现在有点没主意了!哈哈
你们有什么想法吗?
UPDATE:按照@Tenfour04 的建议,我尝试将其调整为我的代码,该代码通过一种方法而不是使用构造函数传递过滤谓词,但它不会编译,除非我替换 "ActivyInfo::comments" 与 "ActivyInfo::comments.name" 之类的东西,但随后 我在调试中为 "searchedProperty(it)" 获得的值是 "name",这不是注释值。
代码如下:
评论适配器:
override fun getFilter(): Filter {
super.setFilter(
{ it.state != ProductState.HIDDEN },
{ ActivyInfo::comments },
compareBy<ProductInfo> { it.state }.thenBy(String.CASE_INSENSITIVE_ORDER) { it.name })
return super.getFilter()
}
基础适配器:
lateinit var defaultFilterPredicate : (T) -> Boolean
lateinit var searchedProperty : (T) -> CharSequence
lateinit var orderComparator : Comparator<T>
fun setFilter(defaultPredicate: (T) -> Boolean, property: (T) -> CharSequence, comparator: Comparator<T> ) {
defaultFilterPredicate = defaultPredicate
searchedProperty = property
orderComparator = comparator
}
override fun performFiltering(constraint: CharSequence): FilterResults {
...
filteredList = sourceList.filter {
constraintRegex.containsMatchIn(Normalizer.normalize(searchedProperty(it), Normalizer.Form.NFD).replace("[^\p{ASCII}]".toRegex(RegexOption.IGNORE_CASE), ""))
}
...
}
您可以将 属性 指定为函数的参数传递给构造函数。
abstract class BaseFirestoreAdapter<T : BaseFirestoreAdapter.DataInterface, VH : RecyclerView.ViewHolder>(val filteredProperty: (T) -> CharSequence) : RecyclerView.Adapter<VH>(), Filterable
{
var sourceList: MutableList<T> = ArrayList()
// ...
override fun performFiltering(keyword: CharSequence): FilterResults {
val keywordRegex = keyword.toString().toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.LITERAL))
filteredList = sourceList.filter {
keywordRegex.containsMatchIn(Normalizer.normalize(filteredProperty(it), Normalizer.Form.NFD).replace("[^\p{ASCII}]".toRegex(RegexOption.IGNORE_CASE), ""))
}
results.values = filteredList.sortedWith(orderComparator)
results.count = filteredList.size
}
...
}
我对你的所做的更改是添加构造函数参数 filteredProperty
,将 sourceList
类型更改为 T
,并将 it.name
替换为 filteredProperty(it)
.
所以子类必须调用这个超级构造函数,像这样传递 属性:
data class SomeData(val comments: String)
class SomeDataAdapter: BaseFirestoreAdapter<SomeData>(SomeData::comments) {
//...
}
或者如果你想保持它的通用性:
class SomeDataAdapter(filteredProperty: (T) -> CharSequence): BaseFirestoreAdapter<SomeData>(filteredProperty) //...