Kotlin, how to test (int)array - kotlin

I'd like to find a nice and concise way to test intarray
at first I tried
mFaces[0].mIndices shouldBe intArrayOf(0, 1, 2)
where mIndices is
var mIndices: IntArray = IntArray(0)
but fails. Intellij also suggests me to override equals() with Arrays
Then I wanted to try something like this
mFaces[0].mIndices.all { it. == index } shouldBe true
but it looks like there is no way to retrieve the index of it inside all{..} or is this
var p = 0
mFaces[0].mIndices.all { it == p++ } shouldBe true
the only possibility?

In Java (Kotlin) arrays are compared by reference, not by content. That means that intArrayOf(1, 2, 3) != intArrayOf(1, 2, 3).
To compare content of arrays you have 2 options:
Use deep comparison:
Arrays.deepequals(mFaces[0].mIndices, intArrayOf(0, 1, 2))
Use lists:
mFaces[0].mIndices.toList() == listOf(0, 1, 2)

Related

Is there an easy way to multiply each element with each other in array / list - Kotlin?

I have got {1,2,3} / or it might be a list<Int> is there an easy way to multiply each element with each other like 1*2 , 1*3, 2*3 ?
This should work, given that you probably don't want to include the duplicates like items[i] * items[j] and items[j] * items[i]
val items = listOf(1, 2, 3, 4)
val result = items.flatMapIndexed { index, a ->
items.subList(index + 1, items.size).map { b -> a * b }
}
println(result) // [2, 3, 4, 6, 8, 12]
flatMapIndexed builds a list for each of the items elements by evaluating the lambda on the index and the item, and then concatenates the lists.
subList is an efficient way to take the items in the specific range: starting at the next index, and until the end of the list.
You can try the old-fashioned way: nested loops
fun main(args: Array<String>) {
val list = listOf( 1, 2, 3 )
for (i in list.indices) {
for (j in (i + 1) until list.size) {
println("${list[i]} * ${list[j]} = ${list[i] * list[j]}")
}
}
}
Output of this code:
1 * 2 = 2
1 * 3 = 3
2 * 3 = 6
If you did want all the permutations (every possible ordering), you could do something like this:
val result = with(items) {
flatMapIndexed { i, first ->
slice(indices - i).map { second -> // combine first and second here }
}
}
slice lets you provide a list of indices for the elements you want to pull, so you can easily exclude the current index and get all the other elements to combo it with. Takes an IntRange too, so you can do slice(i+1 until size) to get the combination (every pairing) functionality too.
Not as efficient as hotkey's subList version (since that doesn't make a copy) but you can get two behaviours this way so I thought I'd mention it! But if I were making a reusable function rather than a quick one-liner, I'd probably go with deHaar's approach with the nested for loops, it's efficient and easy enough to tweak for either behaviour

What is the function of the * operation in Kotlin?

The Code A is from the offical sample project.
I don't understand what val tasks = remember { mutableStateListOf(*allTasks) } mean, could you tell me ?
BTW, Android Studio give me some information, you can see Image A
Code A
#Composable
fun Home() {
// String resources.
val allTasks = stringArrayResource(R.array.tasks)
val allTopics = stringArrayResource(R.array.topics).toList()
// The currently selected tab.
var tabPage by remember { mutableStateOf(TabPage.Home) }
// True if the whether data is currently loading.
var weatherLoading by remember { mutableStateOf(false) }
// Holds all the tasks currently shown on the task list.
val tasks = remember { mutableStateListOf(*allTasks) }
...
}
Image A
From the documentation of varargs:
When you call a vararg -function, you can pass arguments individually, for example asList(1, 2, 3). If you already have an array and want to pass its contents to the function, use the spread operator (prefix the array with *):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
As you see, it expands an array to multiple values for use in a vararg. If you havd an array containing the elements 1, 2, 3, you can pass *yourArray to a method that is equivalent to yourMethod(1,2,3).
In Kotlin * is the Spread Operator.
From docs :
When you call a vararg -function, you can pass arguments individually, for example asList(1, 2, 3). If you already have an array and want to pass its contents to the function, use the spread operator (prefix the array with *):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
In this case tasks will contain the list of strings from R.array.tasks

Idiomatically group String (count consecutively repeated characters)

How with what idioms do I achieve the desired effect?
val input = "aaaabbbcca"
val result = input.(here do the transformations)
val output = listOf("a" to 4, "b" to 3, "c" to 2, "a" to 1)
assert(result == output)
Here's a fun way to do it immutably using fold
fun main() {
val result = "aaaabbbcca"
.chunked(1)
.fold(emptyList<Pair<String, Int>>()) { list, current ->
val (prev, count) = list.lastOrNull() ?: Pair(current, 0)
if (prev == current) list.dropLast(1) + Pair(current, count + 1)
else list + Pair(current, 1)
}
val output = listOf("a" to 4, "b" to 3, "c" to 2, "a" to 1)
check(result == output)
println(result)
}
Output:
[(a, 4), (b, 3), (c, 2), (a, 1)]
This is a tricky little problem, and I can't find a particular idiomatic solution.
However, here's one that's quite concise:
val result = input.replace(Regex("(.)(?!\\1)(.)"), "$1§$2")
.split("§")
.map{ Pair(it[0], it.length) }
It uses a complicated little regex to insert a marker character (§ here, though of course it would work with any character that can't be in the input) between every pair of different characters.  ((?…) is a zero-width look-ahead assertion, so (?!\1) asserts that the next character is different from the previous one.  We need to include the next character in the match, otherwise it'll append a marker after the last character too.)
That gives aaaa§bbb§cc§a in this case.
We then split the string at the marker, giving a list of character groups (in this case "aaaa", "bbb", "cc", "a"), which it's easy to convert into (character,length) pairs.
Using a regex is not always a good solution, especially when it's complicated and unintuitive like this one.  So this might not be a good choice in production code.  On the other hand, a solution using fold() or reduce() probably wouldn't be that much easier to read, either.  In fact, the most maintainable solution might be the old-fashioned one of looping over the characters…
I believe there are no good (efficient, readable) idiomatic ways to solve this. We can use a good, old and boring loop approach. To make it at least a little more funny, we can do it with a lazy computing, utilizing coroutines:
fun String.countConsecutive() = sequence {
if (isEmpty()) return#sequence
val it = iterator()
var curr = it.next()
var count = 1
it.forEach {
if (curr == it) {
count++
} else {
yield(curr.toString() to count)
curr = it
count = 1
}
}
yield(curr.toString() to count)
}
This is good if our string is very long and we only need to iterate over consecutive groups. Even better if we don't need to iterate over all of them.

How I can return IntArray with reduce or fold?

I have the following data for my task:
Input: nums = [1,2,3,4]
Output: [1,3,6,10]
Explanation: Running sum is obtained as follows: [1, 1+2, 1+2+3, 1+2+3+4].
As u see, I need to return IntArray, the first thing I used was runningReduce() , but this function is used in the version of Kotlin 1.4.30.
fun runningSum(nums: IntArray): IntArray {
return nums.runningReduce { sum, element -> sum + element }.toIntArray()
}
Yes, this solution works, but how can I solve the same problem using reduce() or fold()?
Try the following:
nums.fold(listOf(0)) { acc, i -> acc + (acc.last() + i) }.drop(1).toIntArray()
The solution is sub-optimal though: it copies the list in each iteration. But looks fancy.
To avoid copying, you could write it as follows:
nums.fold(mutableListOf(0)) { acc, i -> acc += (acc.last() + i); acc }.drop(1).toIntArray()
I think I prefer the first version, the second one is not pure from functional perspective.
Mafor is right, fold() is not a good choice when producing a collection because it copies the collection every time so you need to workaround with mutable collections, which defeats the point of the functional style.
If you really want to work with arrays, which are mutable, doing it the old fashioned procedural way may be best:
val array = intArrayOf(1, 2, 3, 4)
for (i in array.indices.drop(1)) {
array[i] += array[i - 1]
}
println(array.joinToString(", "))
Here's a slightly modified version of Mafor's answer that gives you an IntArray and avoids the use of multiple statements - it still uses the mutable list though:
val input = intArrayOf(1, 2, 3, 4)
val output = input.fold(mutableListOf(0)) { acc, cur ->
acc.apply { add(last() + cur) }
}.drop(1).toIntArray()
println(output.joinToString(", "))
Both of these print 1, 3, 6, 10.

Increment an integer Map value in Kotlin

Given a Map or MutableMap:
val scores: MutableMap<String, Int> = mutableMapOf(
"some person" to 0,
"some other person" to 0,
"you" to 0,
"me" to 0
)
I am unable to increment these as I would in Python, and I'm not sure what the proper way to do it is, or if it is even possible.
fun test() {
scores["you"] += 2
}
This gives the error:
Operator call corresponds to a dot-qualified call 'scores["you"].plusAssign(2)' which is not allowed on a nullable receiver 'scores["you"]'.
I'm not sure what's going on here.
The top answer contains false information. It does not always look for the plusAssign operator, and you can use indexing along with += in some cases.
According to the actual doc, it first looks for plusAssign, and then uses it if there is no plus operator function available, if there is no plusAssign available, it tries to generate code like: a = a + b.
If you were to use an ArrayList, it can work, for example:
val arr = arrayListOf(1, 2, 3, 4)
arr[0] += 4 // arr[0] = arr[0] + 4 -> arr.set(0, arr.get(0) + 4)
arr // 5, 2, 3, 4
The only problem is that map[key] returns a null reference when the key does not map to a value in the map. So here's another way of doing it, without a dot qualified call:
val map = hashMapOf(1 to 2, 3 to 4)
// map += 1 to map[1]!! + 2 // If you are sure about the key
map += 1 to ((map[1] ?: 0) + 2) // map.put(1, (map.get(1) ?: 0) + 2)
map // { 1: 4, 3: 4 }
You don't even need to use the merge method, simply add an extension function:
operator fun Int?.plus(other: Int) = this?.plus(other) ?: other
fun main() {
val map = hashMapOf(1 to 2, 3 to 4)
map[1] += 2 // map[1] = map[1] + 2 -> map.put(1, map.get(1).plus(2))
}
The += operator is a shorthand operator for the plusAssign function (doc), and is used for adding or replacing entries to a mutable map or collection, as specified by the Kotlin doc for map operations
You can also add new entries to maps using the shorthand operator
form. There are two ways:
plusAssign (+=) operator.
the [] operator alias for set().
When you use scores["you"] += 2, since += is a shorthand operator for plusAssign, and scores["you"] can return a nullable value (as can any get operation on a map), you get the compilation error
Operator call corresponds to a dot-qualified call 'scores["you"].plusAssign(2)' which is not allowed on a nullable receiver 'scores["you"]'.
For your use-case, you can better use the merge method (doc) on the map as below
scores.merge("you", 2, Int::plus)
Do note that merge would add an entry to the map even if the key is absent in the map. In case you want to increment the value for the key only if it's present in the map, you can use the computeIfPresent method (doc) as below
scores.computeIfPresent("you"){ _, v -> v + 2 }