Creating a matrix with values in Kotlin in convenience - kotlin

I want to create the following one with a fancy notation:
arrayOf(intArrayOf(4, 5), intArrayOf(5, 8), intArrayOf(1, 9), intArrayOf(8, 10), intArrayOf(1, 6))
at least, cannot I achieve something that looks as follows:
arrayOf<IntArray>((4, 5), (5, 8), (1, 9), (8, 10), (1, 6))
because it is pretty awkward to rewrite intArrayOf for each row to put in.
Note that I do not ask for the following syntax I'm aware of which is used to initialize an empty matrix with values that are either same or following a common pattern.
val array = Array(row) { IntArray(column) }

val result = listOf(4, 5, 5, 8, 1, 9, 8, 10, 1, 6)
.chunked(2)
.map { it.toIntArray() }
.toTypedArray()
Edit 1:
The calculation could go into an extension function:
fun List<Int>.toArrayOfIntArrays() = this.chunked(2).map { it.toIntArray() }.toTypedArray()
val result = listOf(4, 5, 5, 8, 1, 9, 8, 10, 1, 6).toArrayOfIntArrays()
Edit 2:
Another option – assuming that the inner IntArrays all will consist of exactly two elements – would be to use a user-defined infix function:
infix fun Int.with(i1: Int) = intArrayOf(this, i1)
val result = arrayOf(4 with 5, 5 with 8, 1 with 9, 8 with 10, 1 with 6)
Any word not in conflict with the Kotlin keywords could be used, 'with' is just an example.

If you simply don't like the wordiness of using intArrayOf you could define a shorter name to do the same, for example
fun i(vararg e: Int) = intArrayOf(*e)
And then do
arrayOf(i(4, 5), i(5, 8), i(1, 9), i(8, 10), i(1, 6))

Here is my solution, abusing operator overloading ;)
object Matrix {
operator fun get(vararg rows: IntArray) = rows
operator fun get(vararg values: Int): IntArray = intArrayOf(*values)
}
fun main() {
val result = Matrix.let {
it[
it[1, 2, 3],
it[4, 5, 6],
it[7, 8, 9],
]
}
println(result.toList().map { it.toList() }) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
}
Please don't use it

Related

Tensorflow filter operation on dataset with several columns

I want to create a subset of my data by applying tf.data.Dataset filter operation. I have this data:
data = tf.convert_to_tensor([[1, 2, 1, 1, 5, 5, 9, 12], [1, 2, 3, 8, 4, 5, 9, 12]])
dataset = tf.data.Dataset.from_tensor_slices(data)
I want to retrieve a subset of 'dataset' which corresponds to all elements whose first column is equal to 1. So, result should be:
[[1, 1, 1], [1, 3, 8]] # dtype : dataset
I tried this:
subset = dataset.filter(lambda x: tf.equal(x[0], 1))
But I don't get the correct result, since it sends me back x[0]
Someone to help me ?
I finally resolved it:
a = tf.convert_to_tensor([1, 2, 1, 1, 5, 5, 9, 12])
b = tf.convert_to_tensor([1, 2, 3, 8, 4, 5, 9, 12])
data_set = tf.data.Dataset.from_tensor_slices((a, b))
subset = data_set.filter(lambda x, y: tf.equal(x, 1))

How to I modify arrays inside of a map in Kotlin

I am working with a map with strings as keys and arrays as values. I would like to adjust the map to be the original strings and change the arrays to the average values.
The original map is:
val appRatings = mapOf(
"Calendar Pro" to arrayOf(1, 5, 5, 4, 2, 1, 5, 4),
"The Messenger" to arrayOf(5, 4, 2, 5, 4, 1, 1, 2),
"Socialise" to arrayOf(2, 1, 2, 2, 1, 2, 4, 2)
)
What I have tried to do is:
val averageRatings = appRatings.forEach{ (k,v) -> v.reduce { acc, i -> acc + 1 }/v.size}
However this returns a Unit instead of a map in Kotlin. What am I doing wrong? I am working through a lambda assignment and they want us to use foreach and reduce to get the answer.
You can use forEach and reduce, but it's overkill, because you can just use mapValues and take the average:
val appRatings = mapOf(
"Calendar Pro" to arrayOf(1, 5, 5, 4, 2, 1, 5, 4),
"The Messenger" to arrayOf(5, 4, 2, 5, 4, 1, 1, 2),
"Socialise" to arrayOf(2, 1, 2, 2, 1, 2, 4, 2)
)
val averages = appRatings.mapValues { (_, v) -> v.average() }
println(averages)
Output:
{Calendar Pro=3.375, The Messenger=3.0, Socialise=2.0}
You can do this with mapValues function:
val appRatings = mapOf(
"Calendar Pro" to arrayOf(1, 5, 5, 4, 2, 1, 5, 4),
"The Messenger" to arrayOf(5, 4, 2, 5, 4, 1, 1, 2),
"Socialise" to arrayOf(2, 1, 2, 2, 1, 2, 4, 2)
)
val ratingsAverage = appRatings.mapValues { it.value.average() }
You already got some answers (including literally from JetBrains?? nice) but just to clear up the forEach thing:
forEach is a "do something with each item" function that returns nothing (well, Unit) - it's terminal, the last thing you can do in a chain, because it doesn't return a value to do anything else with. It's basically a for loop, and it's about side effects, not transforming the collection that was passed in and producing different data.
onEach is similar, except it returns the original item - so you call onEach on a collection, you get the same collection as a result. So this one isn't terminal, and you can pop it in a function chain to do something with the current set of values, without altering them.
map is your standard "transform items into other items" function - if you want to put a collection in and get a different collection out (like transforming arrays of Ints into single Int averages) then you want map. (The name comes from mapping values onto other values, translating them - which is why you always get the same number of items out as you put in)

Mapping set of keys to a matching list of lists

What is an idiomatic way to map keys to a matching list of lists? An example - given:
val s = listOf(1, 9)
val u = listOf(listOf(1, 2, 3), listOf(1, 4, 7), listOf(1, 5, 9))
I would like to have a Map<Int, List<List<Int>>> such that every key in s is mapped to a list of lists containing that key:
{1=[ [1, 2, 3], [1, 4, 7], [1, 5, 9] ], 9=[ [1, 5, 9] ]}
The following:
s.groupBy({ it }, { x -> u.filter { it.contains(x) } })
produces:
{1=[[[1, 2, 3], [1, 4, 7], [1, 5, 9]]], 9=[[[1, 5, 9]]]}
which is not quite right and it isn't clear how to flatten the result to the expected shape.
I would recommend associateWith and use it like this:
s.associateWith { num -> u.filter { list -> num in list } }
Output:
{1=[[1, 2, 3], [1, 4, 7], [1, 5, 9]], 9=[[1, 5, 9]]}
I recommended associate at first, but you can shorten the code even further if you use associateWith. Thanks to Abhay Agarwal who recommended it.
Update
You just need to flatten the values of the result Map.
val w = s.groupBy({ it }, { x -> u.filter { it.contains(x) } })
.mapValues { it.value.flatten() }
My solution map the first collection to pairs from each element to the list where it appears, and then groupBy the result list.
Example
val w = s.map { elem -> Pair(elem, u.filter { list -> elem in list }) }
.groupBy ({ it.first }, { it.second })
.mapValues { it.value.flatten() }
check(w[1] == listOf(listOf(1, 2, 3), listOf(1, 4, 7), listOf(1, 5, 9)))
check(w[9] == listOf(listOf(1, 5, 9)))
println(w)
Output
{1=[[1, 2, 3], [1, 4, 7], [1, 5, 9]], 9=[[1, 5, 9]]}
Idiomatic to me would be s.groupBy(....) The answer by #Omar Mainegra - s.groupBy(...).mapValues( flatten ) absolutely works but it looks like a hack where the initial result needs some extra massaging.
The issue is with the implementation of groupBy and more specifically with groupByTo:
public inline fun <T, K, V, M : MutableMap<in K, MutableList<V>>> Iterable<T>.groupByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M {
for (element in this) {
val key = keySelector(element)
val list = destination.getOrPut(key) { ArrayList<V>() }
list.add(valueTransform(element))
}
return destination
}
The implementation wraps the values associated with a key in a list because in general multiple values can be associated with a key which is not the case here
where values in s are unique which means that groupBy is the wrong function to use. The right function is associateWith:
s.associateWith { x -> u.filter { it.contains(x) } }
produces:
{1=[[1, 2, 3], [1, 4, 7], [1, 5, 9]], 9=[[1, 5, 9]]}

Can help make array with only odd numbers from array in Kotlin

I need help. I trying make array only with odd numbers but I don't want use arraylist because I only want array.
Input array like this: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I am trying to get odd only array like : [1, 3, 5, 7, 9]
val array = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val arraylist = arrayListOf<Int>()
for(i in 0..array.size - 1) {
if(array[i] % 2 != 0)
arraylist.add(array[i])
}
val oddarray = arraylist.toArray()
Why not just use filter:
import java.util.Arrays;
fun main(args: Array<String>) {
val numbersArray = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val oddArray = numbersArray.filter{ it % 2 != 0 }.toTypedArray()
print(Arrays.toString(oddArray)) // [1, 3, 5, 7, 9]
}

Swift: for-in with two values

I started learning C some weeks ago and today I started learning Swift. The code is the following:
import Foundation
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
var largest = 0;
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
}
}
}
println(largest);
Why do I need kind in the for-in thingy? For "Prime", "Square", ..., right? Can I work with that somehow, too?
“Add another variable to keep track of which kind of number was the largest, as well as what that largest number was.”
How do I build that in?
import Foundation
var largest = 0;
var largestKind: String?;
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
largestKind = kind;
}
}
}
println("The number \(largest) is from the type \(largestKind)");
That's my solution at the moment. However, the output is
The number 25 is from the type Optional("Square")
How do I get rid of the 'Optional("")? I just want the word Square. I tried removing the question mark (var largestKind: String?; to var largestKind: String;) but I get an error doing that.
For those who have the same question, this is another solution I've found. var largestKind is still optional because of String? but the exclamation mark at the end \(largestKind!) makes it possible to access the value without having that optional stuff around the actual content.
import Foundation
var largest = 0;
var largestKind: String?;
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
largestKind = kind;
}
}
}
println("The number \(largest) is from the type \(largestKind!).");