Reputation: 5459
In Kotlin we can do:
val arr = intArrayOf(1,2,3)
if (2 in arr)
println("in list")
But if I want to check if 2 or 3 are in arr
, what is the most idiomatic way to do it other than:
if (2 in arr || 3 in arr)
println("in list")
Upvotes: 54
Views: 89536
Reputation: 2194
we can use any() funtion and a Set
val arr = intArrayOf(1,2,3)
if(arr.any{ it in setOf(2,3) })
println("in list")
Upvotes: 0
Reputation: 32103
For me, the best way to solve this is to define a containsAny(elements:)
extension function on the Array
and/or Collection
class. All of the places where you need to check whether an Array
or Collection
contains any of the elements of another then remains nice and neat, as follows:
arrayOf(1, 2, 3).containsAny(2, 3)
The implementation detail is tucked away inside of that function and can be changed in a single place in future should you wish to change the implementation.
Here's an example implementation of an extension function defined on the Collection
class, the details of which are inspired by other answers in this thread:
/**
* Returns true if the receiving collection contains any of the specified elements.
*
* @param elements the elements to look for in the receiving collection.
* @return true if any element in [elements] is found in the receiving collection.
*/
fun <T> Collection<T>.containsAny(vararg elements: T): Boolean {
return containsAny(elements.toSet())
}
/**
* Returns true if the receiving collection contains any of the elements in the specified collection.
*
* @param elements the elements to look for in the receiving collection.
* @return true if any element in [elements] is found in the receiving collection.
*/
fun <T> Collection<T>.containsAny(elements: Collection<T>): Boolean {
val set = if (elements is Set) elements else elements.toSet()
return any(set::contains)
}
Likewise, here's an extension function defined on the Array
class:
/**
* Returns true if the receiving array contains any of the specified elements.
*
* @param elements the elements to look for in the receiving array.
* @return true if any element in [elements] is found in the receiving array.
*/
fun <T> Array<T>.containsAny(vararg elements: T): Boolean {
return any(elements.toSet()::contains)
}
Upvotes: 4
Reputation: 7104
You can make an extension function to check for more values:
infix fun <T> Iterable<T>.containsAny(values: Iterable<T>): Boolean =
intersect(values).isNotEmpty()
Upvotes: 3
Reputation: 181
If you use Apache Commons in your project, you can use CollectionUtils.containsAny.
Upvotes: 0
Reputation: 13302
Have a look at this blog post: https://www.codevscolor.com/kotlin-check-array-contains-one-multiple-values
Sample code
fun main() {
val givenArray = intArrayOf(1, 2, 3, 4, 5, 7, 9, 11)
println(givenArray.any{ it == 5 || it == 12})
println(givenArray.any{ it == 5 || it == 11})
println(givenArray.any{ it == 15 || it == 21})
}
Upvotes: 1
Reputation: 29844
This is the shortest and most idiomatic way I can think of using any
and in
:
val values = setOf(2, 3)
val array = intArrayOf(1, 2, 3)
array.any { it in values }
Of course you can use a functional reference for the in
operator as well:
array.any(values::contains)
I use setOf
for the first collection because order does not matter.
Edit: I switched values
and array
, because of alex.dorokhow's answer. The order doesn't matter for the check to work but for performance.
The OP wanted the most idiomatic way of solving this. If you are after a more efficient way, go for aga's answer.
Upvotes: 58
Reputation: 15046
Another handy way is actually not Kotlin's but with use of Java Collections.
It is also good to know it.
Collections.disjoint(Collection<?> c1, Collection<?> c2)
Returns {@code true} if the two specified collections have no elements in common.
@Test
fun disjointCollections() {
val list = listOf(1, 2, 3)
assertTrue(Collections.disjoint(list, listOf(7, 8)))
assertFalse(Collections.disjoint(list, listOf(1)))
}
Upvotes: 5
Reputation: 1228
Combining @aga and @willi-mentzel solutions for better efficiency and dynamic set of checked values:
val numbers = setOf(2, 3)
arrayOf(1, 2, 3).any(numbers::contains)
Is this case the array will be iterated completely only once (at most, in the worst case).
This is more efficient than (suggested by @WilliMentzel):
numbers.any(arrayOf(1, 2, 3)::contains) // don't do that!
Where the array will be iterated set.count times in the worst case.
Note that Set.contains has O(1) complexity, but IntArray::contains has O(N).
Of course, this optimization makes sense only if the set or array are big enough.
Upvotes: 12
Reputation: 691
You can use intersect method, it takes iterable as paramter and returns set containing only items that are both in your collection and in iterable you provided. Then on that set you just need to do size check.
Here is sample:
val array1 = arrayOf(1, 2, 3, 4, 5, 6)
val array2 = arrayOf(2, 5)
// true if array1 contains any of the items from array2
if(array1.intersect(array2.asIterable()).isNotEmpty()) {
println("in list")
}
Upvotes: 25
Reputation: 81879
I think it's most readable to write the statement the other way around:
val arr = intArrayOf(1,2,3)
val match = setOf(2, 3).any(arr::contains)
It might be even possible to use ranges in certain scenarios:
val match = (2..3).any(arr::contains)
In the end, your solution looks pretty good to me already. Although not using fancy library functionality.
Upvotes: 2