In Kotlin, how to check contains one or another value? - arrays

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

I'd use any() extension method:
arrayOf(1, 2, 3).any { it == 2 || it == 3 }
This way, you traverse the array only once and you don't create a set instance just to check whether it's empty or not (like in one of other answers to this question).

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.

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")
}

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.

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

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

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.

You can make an extension function to check for more values:
infix fun <T> Iterable<T>.containsAny(values: Iterable<T>): Boolean =
intersect(values).isNotEmpty()

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

If you use Apache Commons in your project, you can use CollectionUtils.containsAny.

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

Related

How to initial a 2 Dimensions matrix with independent number of rows and columns in Scala?

I've seen something like:
def matInit(n:Int):Array[Array[Int]]={
val maxval=5
val rnd=new Random(100)
Array.tabulate(n){_=>Array.tabulate(n){_=>rnd.nextInt(maxval+1)+1}}
}
but in this template above, the way of initialization is complicated, and the number of rows and columns is equal. Is there an improved way based on it? Thanks.
Array.fill allows creating of 2D arrays and makes the logic a bit simpler.
def matInit(n: Int, m: Int): Array[Array[Int]] = {
val maxval = 5
val rnd = new Random(100)
Array.fill(n, m)(rnd.nextInt(maxval + 1) + 1)
}
This works because fill takes a by name argument which means that the expression is evaluated for each element in the new Array rather than being calculated once and passed as a value.

How to use contains method on a 2D array in scala

I have a 2d array and I want to check whether an array exists inside the 2d array.
I have tried:
var arr = Array(Array(2,1), Array(4,3))
var contain = arr.contains(Array(4, 3))
println(contain)
This should print true but it doesn't work.
Method contains doesn't work because it uses equals to determine equality and for arrays equals is using reference equality, so it will return true only for two references pointing the same object.
You could use find + sameElements:
var arr = Array(Array(2,1), Array(4,3))
var contain = arr.find(_.sameElements(Array(4, 3))).isDefined
println(contain)
Consider using ArrayBuffer instead of Array, if you need mutable collection, like so
val arr = ArrayBuffer(ArrayBuffer(2,1), ArrayBuffer(4,3))
val contain = arr.contains(ArrayBuffer(4, 3))
println(contain)
which outputs
true
Also consider question What is the difference between ArrayBuffer and Array
A more elegant solution would be the following
val array = Array(Array(2,1), Array(4,3))
val result = array.exists(_.sameElements(Array(4, 3)))
println(result)
Output
true

How to remove item from ArrayList in Kotlin

var arrayone: ArrayList<String> = arrayListOf("a","b","c")
val arraytwo:ArrayList<String> = arrayListOf(arrayone.removeAt(0))
for (item in arraytwo) {
println(item)
}
I just want to remove item from the first array and make a new array. But this just prints one item at index 0
removeAt(0) removes the first element from the first list and returns it. arrayListOf then uses that removed item to create a new (the second) list.
arrayone then contains: b and c. arraytwo then contains a.
You may want to use drop instead, if you didn't want to touch the first list and if you only wanted to add the remaining items to the new list, e.g.:
var arrayone: ArrayList<String> = arrayListOf("a","b","c")
val arraytwo = arrayone.drop(1)
for (item in arraytwo) {
println(item) // now prints all except the first one...
}
// arrayone contains: a, b, c
// arraytwo contains: b, c
Or use dropLast(1) if you want to drop only the last item. Or use dropWhile/dropLastWhile if you have a condition to apply and drop all until/upto that condition...
If you really want to remove items from the first and add only the removed ones to the second list, then your current approach is ok. If you however wanted to remove items at specific index and have a new list instead just containing the not-removed ones, you need to construct a copy of the first list first and then apply your removeAt on that list, e.g.:
val arraytwo = arrayone.toMutableList().apply {
removeAt(0)
}
// or without the apply:
arraytwo.removeAt(0)
Or you may use filterIndexed to solve that:
val arraytwo = arrayone.filterIndexed { index, _ ->
index != 1 // you can also specify more interesting filters here...
} // filter, map, etc. all return you a new list. If that list must be mutable again, just add a .toMutableList() at the end
By using filterIndexed, filter, drop, etc. you ensure that the first list is kept untouched. If you didn't want to touch the first list in the first place, you may rather want to use listOf or toList, i.e. just a List as type instead, which does not expose mutable functions (check also Kotlin reference regarding Collections: List, Set, Map).
Maybe you are also interested in filter/filterNot and then soon in minus or similar functions to remove unwanted items without index.
removeAt returns the removed element:
abstract fun removeAt(index: Int): E (source)
Removes an element at the specified index from the list.
Return the element that has been removed.
kotlin.stdlib / kotlin.collections.MutableList.removeAt
You're making a new list with one element, the element you removed.
Try:
val arraytwo = ArrayList(arrayone) // Copy the list
arraytwo.removeAt(0)
You never clarified if you want to modify the original list. If you do, just do arrayone.removeAt(0). That's it.
You can also make use of apply:
val arraytwo = ArrayList(arrayone).apply { removeAt(0) }
If you only need to remove items at the start or end, you can use drop (to remove items at the start) or dropLast, but as far as I know there is no collection extension to drop an item in the middle of an iterable (and judging by your comment, you seem to need this.) This makes sense, since an iterable has no concept of size or index.
If you just want to filter one certain element of your array you can use .filterTo(destination, predicate).
For your example it can look like this:
val arrayone = arrayListOf<String>("a", "b", "c")
val arraytwo = arrayListOf<String>()
arrayone.filterTo(arraytwo, { it != "a" })
println(arrayone) //[a, b, c]
println(arraytwo) //[b, c]
For Normal ArrayList:
val arrList = arrayListOf("account", "bec", "csw", "account")
arrList.removeAll { it == "account" }
For Custom ArrayList:
arrList.removeAll { it.key == "account" }
try this ,
var arrayone: ArrayList<String> = arrayListOf("a","b","c")
arrayone.removeAt(0)
val arraytwo:ArrayList<String> = arrayListOf(arrayone)
for (item in arraytwo) {
println(item)
}
val x = arrayListOf(1, 2, 3, 5)
x.removeFirst()
println(x)
val y = x.filterIndexed { index, value -> index != 0 }
println(y)
Output:
[2, 3, 5]
[3, 5]
GL
Source

Array Contains Too Slow Swift

I have been porting over an algorithm I've been using in Java (Android) to Swift (iOS), and have run into some issues with speed on the Swift version.
The basic idea is there are objects with depths (comment tree), and I can hide and show replies from the dataset by matching against a list of hidden objects. Below is a visualization
Top
- Reply 1
- - Reply 2
- - Reply 3
- Reply 4
and after hiding from the dataset
Top
- Reply 1
- Reply 4
The relevant methods I've converted from Java are as follows
//Gets the "real" position of the index provided in the "position" variable. The comments array contains all the used data, and the hidden array is an array of strings that represent items in the dataset that should be skipped over.
func getRealPosition(position: Int)-> Int{
let hElements = getHiddenCountUpTo(location: position)
var diff = 0
var i = 0
while i < hElements {
diff += 1
if(comments.count > position + diff && hidden.contains(comments[(position + diff)].getId())){
i -= 1
}
i += 1
}
return position + diff
}
func getHiddenCountUpTo(location: Int) -> Int{
var count = 0
var i = 0
repeat {
if (comments.count > i && hidden.contains(comments[i].getId())) {
count += 1
}
i += 1
} while(i <= location && i < comments.count)
return count
}
This is used with a UITableViewController to display comments as a tree.
In Java, using array.contains was quick enough to not cause any lag, but the Swift version calls the getRealPosition function many times when calling heightForRowAt and when populating the cell, leading to increasing lag as more comment ids are added to the "hidden" array.
Is there any way I can improve on the speed of the array "contains" lookups (possibly with a different type of collection)? I did profiling on the application and "contains" was the method that took up the most time.
Thank you
Both Java and Swift have to go through all elements contained in the array. This gets slower and slower as the array gets larger.
There is no a priori reason for Java to fare better, as they both use the exact same algorithm. However, strings are implemented very differently in each language, so that could make string comparisons more expensive in Swift.
In any case, if string comparison slows you down, then you must avoid it.
Easy fix: use a Set
If you want a simple performance boost, you can replace an array of strings with a set of strings. A set in Swift is implemented with a hash table, meaning that you have expected constant time query. In practice, this means that for large sets, you will see better performance.
var hiddenset Set<String> = {}
for item in hidden {
strset.insert(item)
}
For best performance: use a BitSet
But you should be able to do a whole lot better than even a set can do. Let us look at your code
hidden.contains(comments[i].getId()))
If you are always accessing hidden in this manner, then it means that what you have is a map from integers (i) to Boolean values (true or false).
Then you should do the following...
import Bitset;
let hidden = Bitset ();
// replace hidden.append(comments[i].getId())) by this:
hidden.add(i)
// replace hidden.contains(comments[i].getId())) by this:
hidden.contains(i)
Then your code will really fly!
To use a fast BitSet implementation in Swift, include the following in Package.swift (it is free software):
import PackageDescription
let package = Package(
name: "fun",
dependencies: [
.Package(url: "https://github.com/lemire/SwiftBitset.git", majorVersion: 0)
]
)
i think you need the realPosition to link from a tap on a row in the tableview to the source array?
1) make a second array with data only for the tableViewDataSource
copy all visible elements to this new array. create a special ViewModel as class or better struct which only has the nessesary data to display in the tableview. save in this new ViewModel the realdataposition also as value. now you have a backlink to the source array
2) then populate this TableView only from the new datasource
3) look more into the functional programming in swift - there you can nicer go over arrays for example:
var array1 = ["a", "b", "c", "d", "e"]
let array2 = ["a", "c", "d"]
array1 = array1.filter { !array2.contains($0) }
or in your case:
let newArray = comments.filter{ !hidden.contains($0.getId()) }
or enumerated to create the viewmodel
struct CommentViewModel {
var id: Int
var text: String
var realPosition: Int
}
let visibleComments: [CommentViewModel] = comments
.enumerated()
.map { (index, element) in
return CommentViewModel(id: element.getId(), text: element.getText(), realPosition: index)
}
.filter{ !hidden.contains($0.id) }

How to randomly sample from a Scala list or array?

I want to randomly sample from a Scala list or array (not an RDD), the sample size can be much longer than the length of the list or array, how can I do this efficiently? Because the sample size can be very big and the sampling (on different lists/arrays) needs to be done a large number of times.
I know for a Spark RDD we can use takeSample() to do it, is there an equivalent for Scala list/array?
Thank you very much.
An easy-to-understand version would look like this:
import scala.util.Random
Random.shuffle(list).take(n)
Random.shuffle(array.toList).take(n)
// Seeded version
val r = new Random(seed)
r.shuffle(...)
For arrays:
import scala.util.Random
import scala.reflect.ClassTag
def takeSample[T:ClassTag](a:Array[T],n:Int,seed:Long) = {
val rnd = new Random(seed)
Array.fill(n)(a(rnd.nextInt(a.size)))
}
Make a random number generator (rnd) based on your seed. Then, fill an array with random numbers from 0 until the size of your array.
The last step is applying each random value to the indexing operator of your input array. Using it in the REPL could look as follows:
scala> val myArray = Array(1,3,5,7,8,9,10)
myArray: Array[Int] = Array(1, 3, 5, 7, 8, 9, 10)
scala> takeSample(myArray,20,System.currentTimeMillis)
res0: scala.collection.mutable.ArraySeq[Int] = ArraySeq(7, 8, 7, 3, 8, 3, 9, 1, 7, 10, 7, 10,
1, 1, 3, 1, 7, 1, 3, 7)
For lists, I would simply convert the list to Array and use the same function. I doubt you can get much more efficient for lists anyway.
It is important to note, that the same function using lists would take O(n^2) time, whereas converting the list to arrays first will take O(n) time
If you want to sample without replacement -- zip with randoms, sort O(n*log(n), discard randoms, take
import scala.util.Random
val l = Seq("a", "b", "c", "d", "e")
val ran = l.map(x => (Random.nextFloat(), x))
.sortBy(_._1)
.map(_._2)
.take(3)
Using a for comprehension, for a given array xs as follows,
for (i <- 1 to sampleSize; r = (Math.random * xs.size).toInt) yield a(r)
Note the random generator here produces values within the unit interval, which are scaled to range over the size of the array, and converted to Int for indexing over the array.
Note For pure functional random generator consider for instance the State Monad approach from Functional Programming in Scala, discussed here.
Note Consider also NICTA, another pure functional random value generator, it's use illustrated for instance here.
Using classical recursion.
import scala.util.Random
def takeSample[T](a: List[T], n: Int): List[T] = {
n match {
case n: Int if n <= 0 => List.empty[T]
case n: Int => a(Random.nextInt(a.size)) :: takeSample(a, n - 1)
}
}
package your.pkg
import your.pkg.SeqHelpers.SampleOps
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable
import scala.language.{higherKinds, implicitConversions}
import scala.util.Random
trait SeqHelpers {
implicit def withSampleOps[E, CC[_] <: Seq[_]](cc: CC[E]): SampleOps[E, CC] = SampleOps(cc)
}
object SeqHelpers extends SeqHelpers {
case class SampleOps[E, CC[_] <: Seq[_]](cc: CC[_]) {
private def recurse(n: Int, builder: mutable.Builder[E, CC[E]]): CC[E] = n match {
case 0 => builder.result
case _ =>
val element = cc(Random.nextInt(cc.size)).asInstanceOf[E]
recurse(n - 1, builder += element)
}
def sample(n: Int)(implicit cbf: CanBuildFrom[CC[_], E, CC[E]]): CC[E] = {
require(n >= 0, "Cannot take less than 0 samples")
recurse(n, cbf.apply)
}
}
}
Either:
Mixin SeqHelpers, for example, with a Scalatest spec
Include import your.pkg.SeqHelpers._
Then the following should work:
Seq(1 to 100: _*) sample 10 foreach { println }
Edits to remove the cast are welcome.
Also if there is a way to create an empty instance of the collection for the accumulator, without knowing the concrete type ahead of time, please comment. That said, the builder is probably more efficient.
Did not test for performance, but the following code is a simple and elegant way to do the sampling and I believe can help many that come here just to get a sampling code. Just change the "range" according to the size of your end sample. If pseude-randomness is not enough for your need, you can use take(1) in the inner list and increase the range.
Random.shuffle((1 to 100).toList.flatMap(x => (Random.shuffle(yourList))))

Resources