Поиск элемента, соответствующего предикату в Scala
Я пытаюсь найти коллекцию scala для элемента в списке, который соответствует некоторому предикату. Мне не обязательно нужно возвращаемое значение, просто проверяйте, содержит ли этот список.
В Java я могу сделать что-то вроде:
for ( Object item : collection ) {
if ( condition1(item) && condition2(item) ) {
return true;
}
}
return false;
В Groovy я могу сделать что-то вроде:
return collection.find { condition1(it) && condition2(it) } != null
Какой идиоматический способ сделать это в Scala? Я мог бы, конечно, преобразовать стиль цикла Java в Scala, но я чувствую, что есть более функциональный способ сделать это.
Ответы
Ответ 1
Использовать фильтр:
scala> val collection = List(1,2,3,4,5)
collection: List[Int] = List(1, 2, 3, 4, 5)
// take only that values that both are even and greater than 3
scala> collection.filter(x => (x % 2 == 0) && (x > 3))
res1: List[Int] = List(4)
// you can return this in order to check that there such values
scala> res1.isEmpty
res2: Boolean = false
// now query for elements that definitely not in collection
scala> collection.filter(x => (x % 2 == 0) && (x > 5))
res3: List[Int] = List()
scala> res3.isEmpty
res4: Boolean = true
Но если вам нужно всего лишь проверить exists
:
scala> collection.exists( x => x % 2 == 0 )
res6: Boolean = true
Ответ 2
Тестирование, если существует предикат соответствия значениям
Если вам просто интересно проверить, существует ли значение, вы можете сделать это с помощью... exists
scala> val l=(1 to 4) toList
l: List[Int] = List(1, 2, 3, 4)
scala> l exists (_>5)
res1: Boolean = false
scala> l exists (_<2)
res2: Boolean = true
scala> l exists (a => a<2 || a>5)
res3: Boolean = true
Другие методы (некоторые из них основаны на комментариях):
Подсчет соответствия элементов
Считать элементы, удовлетворяющие предикату (и проверить, если count > 0)
scala> (l count (_ < 3)) > 0
res4: Boolean = true
Возврат первого элемента соответствия
Найдите первый элемент, который удовлетворяет предикату (как было предложено Томером Габелем и Луиджи Плингом, это должно быть более эффективным, потому что оно возвращается, как только он находит один элемент, который удовлетворяет предикату, а не перемещается по всему списку в любом случае)
scala> l find (_ < 3)
res5: Option[Int] = Some(1)
// also see if we found some element by
// checking if the returned Option has a value in it
scala> l.find(_ < 3) isDefined
res6: Boolean = true
Тестирование, если существует точное значение
В простом случае, когда мы на самом деле проверяем только один элемент в списке
scala> l contains 2
res7: Boolean = true
Ответ 3
Способ scala будет использовать exists
:
collection.exists(item => condition1(item) && condition2(item))
А начиная с Java 8 вы можете использовать anyMatch
:
collection.stream().anyMatch(item -> condition1(item) && condition2(item));
что намного лучше, чем равнина для или foreach.
Ответ 4
Отфильтруйте и существуют ключевые слова, чтобы получить соответствующие значения из списков.
val values = List(1,2,3,4,5,6,7,8,9,10,....,1000) //List -1
val factors= List(5,7) // List -2
//To get the factors of List-2 from List-1
values .filter(a => factors.exists(b => a%b == 0)) //Apply different logic for our convenience
Данный код помогает получить совпадающие значения из 2 разных списков