Is there an easy way to multiply each element with each other in array / list - Kotlin? - 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

Related

How to fill a list with all combinations of numbers 1,2,3 which sum up to 12 in Kotlin

I'm trying to solve a challenge in Kotlin and want to figure out the most efficient way.
I must create several lists with all possible combinations of numbers 1,2 and 3. The numbers should sum up to 12. One example is that: (1,2,3,1,2,3). Can someone think of the most efficient way to do that in Kotlin?
Thanks in advance!
Since I was bored.
I suppose one efficient way would be like this. You start with a number, say 1, and take another 1, so you have [1, 1]. If the sum is twelve, you remember the numbers. If it's more than twelve, you discard the last number. And if it's less than twelve, you go two ways; either take yet another number, [1, 1, 1], or increase the last number, [1, 2].
This will give you permutations. To get combinations, do the same, but only ever allow growing sequences of numbers, that is, when a sequence is good, you take [1, 2, 3] but don't take [1, 2, 1].
Here's one implementation. It can be slightly improved further, but should be pretty efficient.
enum class Kind { Permutations, Combinations }
fun getCombinationsOrPermutations(kind: Kind)
= mutableListOf<List<Int>>().also { result ->
fun diveIn(numbers: List<Int>) {
for (number in 1..3) {
if (kind == Kind.Combinations && numbers.isNotEmpty() && numbers.last() > number) continue
val newItems = numbers + listOf(number)
when {
newItems.sum() > 12 -> return
newItems.sum() == 12 -> result.add(newItems)
else -> diveIn(newItems)
}
}
}
diveIn(emptyList())
}
fun main() {
getCombinationsOrPermutations(Kind.Permutations)
.also { println(it.size) }
.map(::println)
}

In Kotlin, can I have two random values with the second one omitting the first random number?

Here is what I am trying to say:
val firstNumbers = (1..69).random()
val secondNumbers = (1..69).random()
I would like the secondNumbers to omit the random number picked in firstNumbers
If you're just generating two numbers, what you could do is lower the upper bound for secondNumbers down to 68, then add 1 if it's greater than or equal to the first number. This will ensure an even distribution:
val firstNumber = (1..69).random()
var secondNumber = (1..68).random()
if (secondNumber >= firstNumber) {
secondNumber += 1
}
For generating more than 2 numbers, the following code should work:
fun randoms(bound: Int, n: Int): List<Int> {
val mappings = mutableMapOf<Int, Int>()
val ret = mutableListOf<Int>()
for (i in 0 until n) {
val num = (1..(bound - i)).random()
ret.add(mappings.getOrDefault(num, num))
mappings.put(num, mappings.getOrDefault(bound - i, bound - i))
}
return ret
}
It tries to emulate Fisher-Yates shuffling while only keeping track of swaps that happened, thus greatly reducing memory usage when n is much less than bound. If n is very close to bound, then the answer by #lukas.j is much cleaner to use and probably also faster.
It can be used like so:
randoms(69, 6) // might return [17, 36, 60, 48, 69, 21]
(I'd encourage people to double-check the uniformity and correctness of the algorithm, but it seems good to me)
random() is the wrong approach, rather use shuffled() and then take the first two elements from the list with take(). And it is a oneliner:
val (firstNumber, secondNumber) = (1..69).shuffled().take(2)
println(firstNumber)
println(secondNumber)
Another approach could be to find one number in range 1..69, remove that number from the range and find the second one.
val first = (1..69).random()
val second = ((1..69) - first).random()
Edit: As per your comment, you want 6 different numbers within this range. You can do that like this.
val values = (1..69).toMutableList()
val newList = List(6) {
values.random().also { values.remove(it) }
}

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.

Kotlin - How to split list of strings based on the total length of characters

I am writing a program in Kotlin that is posting messages to a rest endpoint.
val messages : List<String> = getMessageToSend();
webClient
.post()
.uri { builder -> builder.path("/message").build() }
.bodyValue(PostMessageRequest(
messages.joinToString("\n")
))
.exchange()
.block()
However, the rest endpoint has a limit on the maximum size of messages sent. I'm fairly new to Kotlin, but I was looking for a functional way to achieve this, and i'm struggling. I know how I would write this in Java, but i'm keen to do it right. I want to split the messages list into a list of lists, with each list limited to the maximum size allowed and only whole strings added, and then post them individually. I've had a look at methods like chunked, but that doesn't seem flexible enough to achieve what i'm trying to do.
For example, if my message was [this, is, an, example] and the limit was 10, i'd expect my list of lists to be [[this, is an], [example]]
Any suggestions would be massively appreciated.
This looks rather like a situation I've hit before.  To solve it, I wrote the following general-purpose extension function:
/**
* Splits a collection into sublists not exceeding the given size. This is a
* generalisation of [List.chunked]; but where that limits the _number_ of items in
* each sublist, this limits their total size, according to a given sizing function.
*
* #param maxSize None of the returned lists will have a total size greater than this
* (unless a single item does).
* #param size Function giving the size of an item.
*/
inline fun <T> Iterable<T>.chunkedBy(maxSize: Int, size: T.() -> Int): List<List<T>> {
val result = mutableListOf<List<T>>()
var sublist = mutableListOf<T>()
var sublistSize = 0L
for (item in this) {
val itemSize = item.size()
if (sublistSize + itemSize > maxSize && sublist.isNotEmpty()) {
result += sublist
sublist = mutableListOf()
sublistSize = 0
}
sublist.add(item)
sublistSize += itemSize
}
if (sublist.isNotEmpty())
result += sublist
return result
}
The implementation's a bit hairy, but it's pretty straightforward to use.  In your case, I expect you'd do something like:
messages.chunkedBy(1024){ length + 1 }
.map{ it.joinToString("\n") }
to give a list of strings, each no more than 1024 chars*. (The + 1 is of course to allow for the newline characters.)
I'm surprised something like this isn't in the stdlib, to be honest.
(* Unless any of the initial strings is longer.)
You can split a List into chunks of a given length by using chunked like this
fun main() {
val messages = listOf(1, 2, 3, 4, 5, 6)
val chunks = messages.chunked(3)
println("$messages ==> $chunks")
}
This prints
[1, 2, 3, 4, 5, 6] ==> [[1, 2, 3], [4, 5, 6]]

Compare value against two values with 'or' operator

I have a simple if () condition which needs to check if value is either 1 or 2 (for example). Let's say the value we are comparing against is not 'simple':
if(it.first().property.value == 1 || it.first().property.value == 2) {
// Do stuff
}
Is there a better way to perform this check (without typing the entire expression to get the actual value twice)? The only thing that comes to mind is
if(listOf(1, 2).contains(it.first().property.value)) {
// Do stuff
}
But I'm afraid it's more memory consuming since it has additional list introduced.
Your last suggestion is a good one in general, though it's usually better to use a predefined list (and the in operator):
// At the top level, or in a (companion) object:
val acceptableValues = listOf(1, 2)
// Then in the relevant part of the code:
if (it.first().property.value in acceptableValues)
// Do stuff
That only allocates the list once, and performance is about as good as any other option.  It's also very readable, and general.
(If the list doesn't naturally fit into a named property, you'd have to judge how often it might be needed, in order to trade a minor performance benefit against the conciseness of putting it directly in the condition.)
In fact, because you're looking for consecutive integers, there's a more concise option for this particular test:
if (it.first().property.value in 1..2)
// Do stuff
That would work whenever the acceptable values form an (uninterrupted) range.
Alternatively, if you're always checking against exactly two values, you could write a simple extension function:
fun <T> T.isEither(a: T, b: T) = this == a || this == b
(You could write a more general one using a vararg param, but that would create an array each time — very similar to the in listOf() case we started with.)
You can decide it using a when expression like in this example:
fun main() {
val number = 22
when (number) {
1, 2 -> println("${number} is 1 or 2")
in 10..20 -> println("${number} is between 10 and 20 (inclusively)")
else -> println("${number} is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above")
}
}
The output here is
22 is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above
You could define an extension function on the type of it to make it more readable:
if(it.isOneOrTwo()) {
// Do stuff
}
Not sure what's the type of your it, replace TYPEOFIT accordingly:
private inline fun TYPEOFIT.isOneOrTwo() = first().property.value == 1 || first().property.value == 2
To additionally improve the condition you could leverage when:
private inline fun TYPEOFIT.isOneOrTwo() = when(first().property.value) {
1,2 -> true
else -> false
}