Possibility to reduce nested loops - kotlin

I want to bypass deep nesting of several for-loops when creating a list off all possible Transformations.
Right now, this block of code is used:
val allTransformations = ArrayList<Transformation>().apply {
for (moveZ in 0..4)
for (moveY in 0..4)
for (moveX in 0..4)
for (rotateZ in 0..3)
for (rotateY in 0..3)
for (rotateX in 0..3)
add(Transformation(rotateX, rotateY, rotateZ, moveX, moveY, moveZ))
}
Although this is quite straight forward, I was wondering if Kotlin provides other tools to write this in a single line.
I want to retrieve the same list, with less code and see if this results in less clutter.

This solution can be invoked with:
loopOverRanges(0..4, 0..4, 0..4, 0..3, 0..3, 0..3) { result ->
// result[0], result[1], result[2], result[3], result[4], result[5]
}
This is defined as such:
fun loopOverRanges(
vararg ranges: IntRange,
function: (IntArray) -> Unit
) {
val result = IntArray(ranges.size) { index -> ranges[index].first }
val productOfRangeLengths = ranges
.map { it.toList().size }
.product()
for (i in 0 until productOfRangeLengths) {
function(result)
result[0] += ranges[0].step
for (rangeIndex in 0 until ranges.size - 1) {
if (result[rangeIndex] == ranges[rangeIndex].last) {
result[rangeIndex] = ranges[rangeIndex].first
result[rangeIndex + 1] += ranges[rangeIndex].step
}
}
}
}
It's questionable to say the least if this improves readability. It removes the need for nesting, which can be useful for a large amount of ranges. It does not give the instant recognition of my initial nested loop; it also hides named parameters and may throw an IndexOutOfBounds when result[TOO_HIGH_INT] is retrieved.
It was a fun little investigation, but I lean towards not using it.

Here is how to do it with one loop. Just like incrementing a counter with 6 digits. When the first digit overflow, carry to the second digit and reset the first digit. etc.
fun loopOverRanges(a:IntRange,b:IntRange,c:IntRange,d:IntRange,e:IntRange,f:IntRange) : ArrayList<Transformation>
{
val x = a.count() * b.count() * c.count() * d.count() * e.count() * f.count()
val list : ArrayList<Transformation> = ArrayList()
var rx = f.first
var ry = e.first
var rz = d.first
var mx = c.first
var my = b.first
var mz = a.first
for(i in 0 until x)
{
list.add(Transformation(rx,ry,rz,mx,my,mz))
when{
rx < f.last -> rx += 1
ry < e.last -> {
rx = f.first
ry += 1
}
rz < d.last -> {
rx = f.first
ry = e.first
rz += 1
}
mx < c.last -> {
rx = f.first
ry = e.first
rz = d.first
mx += 1
}
my < b.last -> {
rx = f.first
ry = e.first
rz = d.first
mx = c.first
my += 1
}
mz < a.last -> {
rx = f.first
ry = e.first
rz = d.first
mx = c.first
my = b.first
mz += 1
}
}
}
}
return list
}
It can be simplified as
fun loopOverRanges(a:IntRange,b:IntRange,c:IntRange,d:IntRange,e:IntRange,f:IntRange) : ArrayList<Transformation>
{
data class Digit(var value :Int, val range:IntRange)
val list : ArrayList<Transformation> = ArrayList()
val digits = arrayOf(Digit(a.first,a),Digit(b.first,b),Digit(c.first,c),Digit(d.first,d),Digit(e.first,e),Digit(f.first,f))
val x = digits.fold(1){acc,digit -> acc * digit.range.count() }
for(i in 0 until x)
{
list.add(Transformation(digits[5].value,digits[4].value,digits[3].value,digits[2].value,digits[1].value,digits[0].value))
val j = digits.indexOfFirst { it.value < it.range.last }
if(j >= 0)
{
for(k in 0 until j )
{
digits[k].value = digits[k].range.first
}
digits[j].value += 1
}
}
return list
}

Related

Read a sequence of numbers of undefined size & print the largest number & position of its first occurrence

I need to read a sequence of numbers of undefined size & prints the largest number & the position of its first occurrence
Can anyone help with this code:
import java.util.Scanner
fun main() {
val scan = Scanner(System.`in`)
val num = scan.nextInt()
var max = Int.MIN_VALUE
var pos = 0
var i = 1
do {
if (max < num) {
max = num
pos = i
}
i++
} while (scan.hasNext())
print("$max $pos")
}
You just need to read a new number in each iteration:
import java.util.Scanner
fun main() {
val scan = Scanner(System.`in`)
var max = Int.MIN_VALUE
var pos = 0
var i = 1
while (scan.hasNext()) {
// Read a new number here
val num = scan.nextInt()
if (max < num) {
max = num
pos = i
}
i++
}
print("$max $pos")
}
My solution to this task
This is a simple task, it can be solved in a simple way without using a “java.util.Scanner”. You just need to read a new number in each iteration.
fun main() {
var pos = 0
var max = 0
var count = 1
while (true) {
val input = readlnOrNull()
if (input == null) break
val num = input.toInt()
if (pos == 0 || num > max) {
max = num
pos = count
}
count++
}
print("$max $pos")
}

Kotlin - The caracter literal does not conform expect type Int

I'm struggling with types with my program, I've been asked to do it in JS first and it worked fine but now I can't achieve the result.
Do you think I should make another 'algorithm' ? In advance, thank you for your time.
fun main(){
// the idea is to put numbers in a box
// that cant be larger than 10
val data = "12493419133"
var result = data[0]
var currentBox = Character.getNumericValue(data[0])
var i = 1
while(i < data.length){
val currentArticle = Character.getNumericValue(data[i])
currentBox += currentArticle
println(currentBox)
if(currentBox <= 10){
result += Character.getNumericValue(currentArticle)
}else{
result += '/'
//var resultChar = result.toChar()
// result += '/'
currentBox = Character.getNumericValue(currentArticle)
result += currentArticle
}
i++
}
print(result) //should print 124/9/341/91/33
}
The result is actually of a Char type, and the overload operator function + only accepts Int to increment ASCII value to get new Char.
public operator fun plus(other: Int): Char
In idomatic Kotlin way, you can solve your problem:
fun main() {
val data = "12493419133"
var counter = 0
val result = data.asSequence()
.map(Character::getNumericValue)
.map { c ->
counter += c
if (counter <= 10) c.toString() else "/$c".also{ counter = c }
}
.joinToString("") // terminal operation, will trigger the map functions
println(result)
}
Edit: If the data is too large, you may want to use StringBuilder because it doesn't create string every single time the character is iterated, and instead of using a counter of yourself you can use list.fold()
fun main() {
val data = "12493419133"
val sb = StringBuilder()
data.fold(0) { acc, c ->
val num = Character.getNumericValue(c)
val count = num + acc
val ret = if (count > 10) num.also { sb.append('/') } else count
ret.also { sb.append(c) } // `ret` returned to ^fold, next time will be passed as acc
}
println(sb.toString())
}
If you want a result in List<Char> type:
val data = "12493419133"
val result = mutableListOf<Char>()
var sum = 0
data.asSequence().forEach {
val v = Character.getNumericValue(it)
sum += v
if (sum > 10) {
result.add('/')
sum = v
}
result.add(it)
}
println(result.joinToString(""))

Kotlin: Run length encoding

The program works, however, I still get a logical error: the final letter doesn't run through. For example, when I enter aaaabbbbccccdddd the output I get is a4b4c4 but there is no d4.
fun main () {
val strUser = readLine()!!.toLowerCase()
val iLength = strUser!!.length
var iMatch : Int = 0
var chrMatch : Char = strUser[0]
for (i in 0..iLength) {
if (strUser[i] == chrMatch) {
iMatch += 1
}else {
print("$chrMatch$iMatch")
chrMatch = strUser[i]
iMatch = 1
}
}
}
There are many solutions, but the best is RegExp
fun encode(input: String): String =
input.replace(Regex("(.)\\1*")) {
String.format("%d%s", it.value.length, it.groupValues[1])
}
demo
Test result
println(encode("aaaabbbbccccdddd")) // 4a4b4c4d
strUser contains chars by indexes from 0 to iLength - 1 so you have to write for (i in 0 until iLength) instead of for (i in 0..iLength)
But Tenfour04 is completely right, you can just iterate strUser without indexes:
fun main() {
val strUser = readLine()!!.toLowerCase()
var iMatch: Int = 0
var chrMatch: Char = strUser[0]
for (char in strUser) {
if (char == chrMatch) {
iMatch += 1
} else {
print("$chrMatch$iMatch")
chrMatch = char
iMatch = 1
}
}
}
fun main () {
val strUser = readLine()!!.toLowerCase()
var iMatch : Int = 0
var chrMatch : Char = strUser[0]
for (char in strUser+1) {
if (char == chrMatch) {
iMatch += 1
}else {
print("$chrMatch$iMatch")
chrMatch = char
iMatch = 1
}
}
}
fun runLengthEncoding(inputString: String): String {
val n=inputString.length
var i : Int =0
var result : String =""
while(i<n){
var count =1
while(i<n-1 && inputString[i] == inputString[i+1]){
count ++
i++
}
result=result.toString()+count.toString()+inputString[i].toString()
i++
}
return result
}

A very basic exercise help-----Kotlin

Im trying to do this exercise
https://www.hackerrank.com/challenges/compare-the-triplets/problem?h_r=next-challenge&h_v=zen
I already wrote the code but the result is not right and for my eyes its all good
Could somebody pls tell me whats wrong??
thx
import java.util.Scanner
fun main(){
var loop = 0
var score = Array<Int>(2){0}
val reader = Scanner(System.`in`)
var alice:String = readLine().toString()
var bob:String = readLine().toString()
val numerosa: List<String> = alice.split(" ")
val numerosb:List<String> = bob.split(" ")
for(a in 3..3) {
when (numerosa[loop].toInt()) {
in numerosb[loop].toInt() + 1..100 -> score[0] += 1
in numerosb[loop].toInt() - 1..0 -> score[1] += 1
}
loop += 1
}
println("${score[0]} ${score[1]}")
}
You could do it something like this, you have multiple variables which were not required so I cleaned up the code.
val score = Array(2) { 0 }
val aliceNumbers = readLine()!!.split(" ").map(String::toInt)
val bobNumbers = readLine()!!.split(" ").map(String::toInt)
require(aliceNumbers.size == 3 && bobNumbers.size == 3) { "There must be 3 numbers for each" }
require(!aliceNumbers.any { it !in 1..100 } || !bobNumbers.any { it !in 1..100 }) { "Numbers must be in range 1 to 100" }
for (a in 0..2) {
if(aliceNumbers[a] > bobNumbers[a]) score[0] += 1
if(aliceNumbers[a] < bobNumbers[a]) score[1] += 1
}
println("${score[0]} ${score[1]}")

Kotlin decomposing numbers into powers of 2

Hi I am writing an app in kotlin and need to decompose a number into powers of 2.
I have already done this in c#, PHP and swift but kotlin works differently somehow.
having researched this I believe it is something to do with the numbers in my code going negative somewhere and that the solution lies in declaring one or more of the variable as "Long" to prevent this from happening but i have not been able to figure out how to do this.
here is my code:
var salads = StringBuilder()
var value = 127
var j=0
while (j < 256) {
var mask = 1 shl j
if(value != 0 && mask != 0) {
salads.append(mask)
salads.append(",")
}
j += 1
}
// salads = (salads.dropLast()) // removes the final ","
println("Salads = $salads")
This shoud output the following:
1,2,4,8,16,32,64
What I actually get is:
1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,-2147483648,
Any ideas?
This works for the one input that you specified, at the very least:
fun powersOfTwo(value :Long): String {
val result = ArrayList<String>()
var i = 0
var lastMask = 0
while (lastMask < value) {
val mask = 1 shl i
if (value != 0.toLong() && mask < value) {
result.add(mask.toString())
}
lastMask = mask
i += 1
}
return result.joinToString(",")
}
Ran it in a unit test:
#Test
fun addition_isCorrect() {
val result = powersOfTwo(127)
assertEquals("1,2,4,8,16,32,64", result)
}
Test passed.
You can get a list of all powers of two that fit in Int and test each of them for whether the value contains it with the infix function and:
val value = 126
val powersOfTwo = (0 until Int.SIZE_BITS).map { n -> 1 shl n }
println(powersOfTwo.filter { p -> value and p != 0}.joinToString(","))
// prints: 2,4,8,16,32,64
See the entire code in Kotlin playground: https://pl.kotl.in/f4CZtmCyI
Hi I finally managed to get this working properly:
fun decomposeByTwo(value :Int): String {
val result = ArrayList<String>()
var value = value
var j = 0
while (j < 256) {
var mask = 1 shl j
if ((value and mask) != 0) {
value -= mask
result.add(mask.toString())
}
j += 1
}
return result.toString()
}
I hope this helps someone trying to get a handle on bitwise options!
Somehow you want to do the "bitwise AND" of "value" and "mask" to determine if the j-th bit of "value" is set. I think you just forgot that test in your kotlin implementation.