首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在检查几个已知值时简化谓词

在检查几个已知值时简化谓词
EN

Stack Overflow用户
提问于 2018-08-28 16:50:24
回答 3查看 113关注 0票数 1

Kotlin经常使用非常务实的方法。我想知道是否有一些我不知道的方法来简化只要求一些已知值的过滤谓词。

例如,考虑以下列表:

代码语言:javascript
复制
val list = listOf("one", "two", "2", "three")

要过滤出"two""2"过滤,可以通过几种方式完成,例如:

代码语言:javascript
复制
list.filter {
  it in listOf("two", "2") // but that creates a new list every time... (didn't check though)
}

// extracting the list first, uses more code... and may hide the list somewhere sooner or later
val toCheck = listOf("two", "2")
list.filter { it in toCheck } 

// similar, but probably less readable due to naming ;-)
list.filter(toCheck::contains)

// alternative using when, but that's not easier for this specific case and definitely longer:
list.filter {
    when (it) {
        "two", "2" -> true
        else -> false
    } 
}

// probably one of the simplest... but not so nice, if we need to check more then 2 values
list.filter { it == "two" || it == "2" }

我想知道..。有没有像list.filter { it in ("two", "2") }这样的东西或任何其他简单的方法来为已知值/常量创建/使用短谓词?最后,这就是我想要检查的全部内容。

编辑:我刚刚意识到这个示例没有多大意义,因为listOf("anything", "some", "other").filter { it in listOf("anything") }总是:listOf("anything")。然而,列表交集在处理的星座中是有意义的,例如Map。在过滤器实际上不只返回过滤值的地方(例如.filterKeys)。然而,减法(即list.filterNot { it in listOf("two", "2") })在列表中也是有意义的。

EN

回答 3

Stack Overflow用户

发布于 2018-08-28 17:06:09

Kotlin在集合上提供了一些集合操作,这些集合是

  • intersect (两个集合在common)
  • union中拥有的内容)(将两个collections)
  • subtract (不包含另一个元素的集合)组合在一起)

在您的示例中,您可以使用设置操作subtract而不是过滤器

代码语言:javascript
复制
val filteredList  = list.subtract(setOf("two","2"))

这就对了。

编辑:

有趣的(双关语)还不止于此:您可以使用自己的函数来扩展集合,比如丢失的outerJoin,或者用于过滤的函数,比如without或运算符,比如用于intersect/

例如,通过添加这些

代码语言:javascript
复制
infix fun <T> Iterable<T>.without(other Iterable<T>) = this.subtract(other)
infix fun <T> Iterable<T>.excluding(other Iterable<T>) = this.subtract(other)

operator fun <T> Iterable<T>.div(other: Iterable<T>) = this.intersect(other)

您的代码-当使用intersect应用于示例时-将变为

代码语言:javascript
复制
val filtered = list / filter //instead of intersect filter 

或者-而不是减法:

代码语言:javascript
复制
val filtered = list without setOf("two", "2")

代码语言:javascript
复制
val filtered = list excluding setOf("two", "2")

够实际了吗?

票数 2
EN

Stack Overflow用户

发布于 2018-08-28 17:20:23

我认为没有什么比创建过滤列表/集合然后应用它更简单的了:

代码语言:javascript
复制
val toCheck = listOf("two", "2") 
val filtered = list.filter { it in toCheck }

代码语言:javascript
复制
val toCheck = setOf("two", "2")
val filtered = list.filter { it in toCheck } 

但如果您愿意,也可以创建一个Predicate

代码语言:javascript
复制
val predicate: (String) -> Boolean = { it in listOf("2", "two") }
val filtered = list.filter { predicate(it) }

编辑过滤器:至于使用minus的方法,这里没有提到,但它并没有提供简单性或效率,因为它本身使用了

代码语言:javascript
复制
/**
 * Returns a list containing all elements of the original collection except the elements contained in the given [elements] collection.
 */
public operator fun <T> Iterable<T>.minus(elements: Iterable<T>): List<T> {
    val other = elements.convertToSetForSetOperationWith(this)
    if (other.isEmpty())
        return this.toList()
    return this.filterNot { it in other }
}

(来自Collections.kt)

票数 0
EN

Stack Overflow用户

发布于 2018-08-28 18:42:14

现在,我得到了以下结论:

代码语言:javascript
复制
fun <E> containedIn(vararg elements: E) = { e:E -> e in elements }
fun <E> notContainedIn(vararg elements: E) = { e:E -> e !in elements }

它可以用于使用filter的地图和列表,例如:

代码语言:javascript
复制
list.filter(containedIn("two", "2"))
list.filter(notContainedIn("two", "2"))
map.filterKeys(containedIn("two", "2"))
map.filterValues(notContainedIn("whatever"))

事实上,它可以用于任何事情(如果你喜欢的话):

代码语言:javascript
复制
if (containedIn(1, 2, 3)(string.toInt())) {

我的第一种方法受到Gerald Mückes的启发,但使用了minus而不是subtract (所以它只涉及减法部分):

代码语言:javascript
复制
(list - setOf("two", "2"))
       .forEach ...

或者使用自己的扩展函数并使用vararg

代码语言:javascript
复制
fun <T> Iterable<T>.without(vararg other: T) = this - other

使用以下用法:

代码语言:javascript
复制
list.without("two", "2")
    .forEach... // or whatever...

然而,使用上面的变体,就不可能有中缀了。对于只有一次排除的情况,还可以提供中缀...否则,必须实现Iterable-overload:

代码语言:javascript
复制
infix fun <T> Iterable<T>.without(other : T) = this - other
infix fun <T> Iterable<T>.without(other : Iterable<T>) = this - other

用法:

代码语言:javascript
复制
list without "two"
list without listOf("two", "2")
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52053755

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档