Adding a list to the end of another list - kotlin

I am writing a piece of code in which I need to add a list to another list.
fun a(x:Int):List<List<Int>>{
var a = 1.rangeTo(x);
var b: List<List<Int>> = emptyList();
for (i in a){
var num1 = if(i<=3) i else 4;
var list_a= 0.rangeTo(num1 - 1);
b.add(list_a);
}
return b
}
I problem is b.add(list_a) is giving error(unresolved reference).
In this function if I input println(a(2))
The output should be [[0],[0,1]]
Please help.

The reason why you're getting the unresolved reference for b.add() is because you have initialized b as a List instead of MutableList.
Please note that once initialized, you can add elements to a MutableList but not a List in Kotlin. Hence change your initialization of b as var b: MutableList<List<Int>> = mutableListOf()
fun a(x: Int): List<List<Int>> {
var a = 1.rangeTo(x)
var b: MutableList<List<Int>> = mutableListOf()
for (i in a) {
var num1 = if (i <= 3) i else 4
var list_a = 0.rangeTo(num1 - 1).toList()
b.add(list_a)
}
return b
}
Refactoring it a bit further, you can use 1..x for the range in the for loop and (0 until num1) instead of 0.rangeTo(num1 - 1) as below
fun a(x: Int): List<List<Int>> {
val listB: MutableList<List<Int>> = mutableListOf()
for (i in 1..x) {
val num1 = if (i <= 3) i else 4
val listA = (0 until num1).toList()
listB.add(listA)
}
return listB
}

Related

Evaluating a string in kotlin

I wrote a code in kotlin for evaluating a given string from Divison to subtraction, it works but it gives the wrong answer, for example i got a string x in the first line which have answer -215.96666 whereas the answer from code is -237.366666 idk where the error is. i saw more people using stack for doing it, but i wanted to do this way for evaluating a string
var x : String = "5+4-10x20-40/30x20+34/20"
fun div(x: String): String {
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if ("/" in ele1) {
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for (ele2 in lis2) {
if ("/" in ele2) {
val pos3 = lis2.indexOf(ele2)
val lis3 = ele2.split("x").toMutableList()
for (ele3 in lis3) {
if ("/" in ele3) {
val pos4 = lis3.indexOf(ele3)
val lis4 = ele3.split("/")
val div = (lis4[0].toDouble() / lis4[1].toDouble()).toString()
lis3[pos4] = div
}
}
lis2[pos3] = lis3.joinToString("x")
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun mul(x : String) : String{
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if("x" in ele1){
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for(ele2 in lis2){
if("x" in ele2){
val pos2 = lis2.indexOf(ele2)
val lis3 = ele2.split("x")
val mul = (lis3[0].toDouble() * lis3[1].toDouble()).toString()
lis2[pos2] = mul
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun add(x : String): String {
val lis1 = x.split("-").toMutableList()
for(ele1 in lis1){
if("+" in ele1){
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+")
val add = (lis2[0].toDouble() + lis2[1].toDouble()).toString()
lis1[pos1] = add
}
}
return (lis1.joinToString("-"))
}
fun sub(x : String) : String{
val lis1 = x.split("-").toMutableList()
var sub = 0.0
for(ele1 in lis1){
sub -= ele1.toDouble()
}
return (sub.toString())
}
fun eval(x: String): String {
val divanswer = div(x)
val mulanswer = mul(divanswer)
val addanswer = add(mulanswer)
return sub(addanswer)
}
fun main(args: Array<String>){
println(eval(x))
}
i wanted the answer as -215.96666 but the answer given by code is -237.366666
In the case of this specific input, there are two bugs involved.
First bug is related to the fact you first process + and then -, but in mathematics we should process them together, from left to right. As a result, your algorithm processes this: 1-1+1 (correct answer: 1) as: 1-(1+1) (answer: -1). Alternatively, I believe handling - first and then + should work properly.
Second bug is that in sub() you start from 0 and subtract even the first number, but the first number should be actually added or used as an initial value.
I believe after fixing these two bugs, it should provide a correct answer for this specific input, but there are probably more bugs like these. For example, you incorrectly handle chains of the same operator, you only care about the first pair, so 1+1+1 becomes 2 (and then it is turned to -2 due to earlier mentioned bug).
As a general advice, learn to use a debugger and analyze how your data changes while your code is processing it. Even if you simply print your intermediate results: divanswer, mulanswer and addanswer and then run them through Google for processing, you will notice there is a problem somewhere at the add() step. Then rinse and repeat until everything works correctly.
Thanks to #broot for spotting this, the problem was with the addition and subtraction part, now that i merged them into one and got the correct answers for strings i input, here is the full code corrected.
var x : String = "5+4-10x20-40/30x20+34/20"
fun div(x: String): String {
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if ("/" in ele1) {
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for (ele2 in lis2) {
if ("/" in ele2) {
val pos3 = lis2.indexOf(ele2)
val lis3 = ele2.split("x").toMutableList()
for (ele3 in lis3) {
if ("/" in ele3) {
val pos4 = lis3.indexOf(ele3)
val lis4 = ele3.split("/")
val div = (lis4[0].toDouble() / lis4[1].toDouble()).toString()
lis3[pos4] = div
}
}
lis2[pos3] = lis3.joinToString("x")
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun mul(x : String) : String{
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if("x" in ele1){
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for(ele2 in lis2){
if("x" in ele2){
val pos2 = lis2.indexOf(ele2)
val lis3 = ele2.split("x")
val mul = (lis3[0].toDouble() * lis3[1].toDouble()).toString()
lis2[pos2] = mul
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun final(x: String): Double {
val substr = StringBuffer()
var answer = 0.0
var opr = '+'
for(ele in x.indices){
var current = x[ele]
if(current in '0'..'9' || current == '.'){
substr.append(current)
}
if(current == '-' || current == '+'){
var operand = substr.toString().toDouble()
substr.setLength(0)
when (opr){
'+' -> answer += operand
'-' -> answer -= operand
}
opr = current
}
}
val num = substr.toString().toDouble()
when(opr){
'+' -> answer += num
'-' -> answer -= num
}
return answer
}
fun eval(x: String): Double {
val divanswer = div(x)
return final(mul(divanswer))
}
fun main(args: Array<String>){
println(eval(x))
}

Kotlin how to copy class property fields in its own member function

I have the following code, I would like to update the properties in class A, in c++, I can use something like this = A() within the udpate() that invokes implicity operator = ()
data class B(
var A: Int = 10,
var B: Long = 20L,
var C: Double = 200.0
)
data class A(
var a: Int = 0,
var b: Long = 0L
) {
fun badUpdate(input: B) {
var holder = this#A // It does not work, any better way to update within the member function?
holder = A(input.A, input.B)
}
fun aboriginalUpdate(input:B) {
a = input.A // It works, but what if I have 30 properties?
b = input.B
}
fun update(input: B) : A {
return A(input.A, input.B) // Works but not ideal, the return value is not necessary
}
}
fun main() {
var data0 = A()
val data = B(A = 300)
data0.badUpdate(data) // data0.a does not change (nothing invoked in update0)
data0 = data0.update(data)
println("$data0")
}
Any better way to update the properties within the class A?
I thnk 'apply()' is what you are looking for:
data class B(
var a: Int = 10,
var b: Long = 20L,
var c: Double = 200.0
)
data class A(
var a: Int = 0,
var b: Long = 0L
) {
fun goodUpdate(input: B) {
this.apply {
a = input.a
b = input.b
}
}
}
fun main() {
var data0 = A()
val data = B(a = 300)
data0.goodUpdate(data)
println("$data0") // A(a=300, b=20)
}
but unlike in the example you provided from C, you are not creating a new instance, you are updating properties of the existing one, which I believe you wanted
but you can achieve that even simpler, by reassigning object fields:
fun betterUpdate(input: B) {
this.a = input.a
this.b = input.b
}

Is there a function to search in a ArrayList from a position?

I read carefully the ArrayList documentation in Kotlin and apparently there is no way to search a value in ArrayList starting from a pointer. The alternative is write your own function iterating the right elements in ArrayList and testing the condition.
So I've programmed the following code:
fun <T> ArrayList<T>.findNext(cond: (T) -> Boolean, p: Int = 0): Int {
for (i in p..this.lastIndex)
if (cond(this[i])) return i
return -1
}
data class Person (
var name: String,
var age: Int
)
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({it.name=="Paul"})) // 0
println(v.findNext({it.name=="Paul"}, 1)) // 2
println(v.findNext({it.name=="Paul"}, 3)) // -1
}
Is there something better than this?
You can avoid any intermediate collections:
inline fun <T> List<T>.findNext(p: Int = 0, cond: (T) -> Boolean) =
listIterator(p).withIndex().asSequence().find { cond(it.value) }?.let { it.index + p }
By swapping the arguments you can call it like this:
println(v.findNext {it.name=="Paul"}) // 0
println(v.findNext(1) {it.name=="Paul"}) // 2
println(v.findNext(3) {it.name=="Paul"}) // null
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({ it.name == "Paul" },0))//IndexedValue(index=0, value=Person(name=Paul, age=22))
println(v.findNext({ it.name == "Paul" },2))//IndexedValue(index=2, value=Person(name=Paul, age=50))
println(v.findNext({ it.name == "Paul" },3))//null
}
private fun <T> List<T>.findNext(cond: (T) -> Boolean, position: Int): IndexedValue<T>? {
return withIndex().filter { it.index >= position }.firstOrNull { cond(it.value) }
}
maybe use withIndex and a filter ?
val arrayNames = listOf<String>("Paul", "Ann", "Paul", "Roger","Peter")
arrayNames.withIndex().filter {
it.value == "Paul" //value contains the original name
}.forEach{
println(it.index) //indext contains the position.
}
this will give you the output 0 and 2
for your case (person object instead of String) you will use
it.value.name == "Paul"

Convert collection of numbers to range formatted string with Kotlin

I have a very large list of numbers. I need to pass this list of numbers as a URL query parameter. Since these lists can get so large, it could potentially cause the request URL to exceed the allowed length of a URL; also, it's a bit difficult to debug a string of sequential numbers (E.G. 1,2,3,..,500,782). To remedy these issues, I would like to convert the sequential number list string to one that is formatted using a range notation (E.G. -5..-3,1..500,782). How do I create this range notation string using Kotlin and how do I parse the string back to a collection of numbers also using Kotlin?
This will convert a Collection<Int> to a string that uses the "range notation" specified:
fun Collection<Int>.toRangesString(): String {
if (this.isEmpty()) {
return ""
}
if (this.size <= 2) {
return this.toSortedSet().joinToString(",")
}
val rangeStrings = mutableListOf<String>()
var start: Int? = null
var prev: Int? = null
for (num in this.toSortedSet()) {
if (prev == null) {
start = num
prev = num
continue
}
if (num != (prev + 1)) {
_addRangeString(rangeStrings, start!!, prev)
start = num
prev = num
continue
}
prev = num
}
if (start != null) {
_addRangeString(rangeStrings, start, prev!!)
}
return rangeStrings.joinToString(",")
}
private fun _addRangeString(rangeStrings: MutableList<String>, start: Int, prev: Int) {
rangeStrings.add(
when {
(start == prev) -> start.toString()
((start + 1) == prev) -> "${start},${prev}"
else -> "${start}..${prev}"
}
)
}
...and this will parse those range notated strings into a Set<Int>:
fun parseRangesString(str: String): Set<Int> {
if (str.isBlank()) {
return setOf()
}
val ranges = str.trim().split(",")
val numbers = mutableListOf<Int>()
for (range in ranges) {
if (range.contains("..")) {
val (start, end) = range.split("..")
numbers.addAll(start.toInt()..end.toInt())
continue
}
numbers.add(range.toInt())
}
return numbers.toSet()
}
...and, finally, even better than using a huge collection of numbers, you can use Kotlin's IntRange (or LongRange) class:
fun toIntRanges(str: String): Collection<IntRange> = _toRanges(str, ::_createIntRange)
fun toLongRanges(str: String): Collection<LongRange> = _toRanges(str, ::_createLongRange)
private fun <T : ClosedRange<*>> _toRanges(str: String, createRange: (start: String, end: String) -> T): Collection<T> {
if (str.isBlank()) {
return listOf()
}
val rangeStrs = str.trim().split(",")
val ranges = mutableListOf<T>()
for (rangeStr in rangeStrs) {
if (rangeStr.contains("..")) {
val (start, end) = rangeStr.split("..")
ranges.add(createRange(start, end))
continue
}
ranges.add(createRange(rangeStr, rangeStr))
}
return ranges.toList()
}
private fun _createIntRange(start: String, end: String) = IntRange(start.toInt(), end.toInt())
private fun _createLongRange(start: String, end: String) = LongRange(start.toLong(), end.toLong())

List<List<Char>> + List<Char> = List<Any>?

I have a below code which works.
class ListManipulate(val list: List<Char>, val blockCount: Int) {
val result: MutableList<List<Char>> = mutableListOf()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result.add(constructSequence(sequence))
return
}
for (i in start .. list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> {
var result = emptyList<Char>()
for (i in sequence) {
result += list[i]
}
return result
}
}
However, when I change the result from MutableList to normal List, i.e.
var result: List<List<Char>> = emptyList()
// ...
result += constructSequence(sequence)
I got this error Type mismatch. Require: List<List<Char>>; Found: List<Any>
The full code as below
class ListManipulate(val list: List<Char>, val blockCount: Int) {
var result: List<List<Char>> = emptyList()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result += constructSequence(sequence)
return
}
for (i in start .. list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> {
var result = emptyList<Char>()
for (i in sequence) {
result += list[i]
}
return result
}
}
Why result + constructSequence(sequence) would result in List<Any> instead of List<List<Char>>?
Is there a way I could still use the normal List> and not the mutable list?
CTRL + click on the + in IDEA, you'll see that it takes you to the following function:
/**
* Returns a list containing all elements of the original collection and then all elements of the given [elements] collection.
*/
public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> {
/* ... */
}
Which means that you add all the individual elements of elements to the receiver. That is, you'll add all T's to the List<List<T>>. Since List<T> is not T, you'll get List<Any> as a result.
The problem is that += is overloaded. If it sees an Iterable, Array or Sequence it behaves differently. You have to explicitly use plusElement() to achieve the behaviour you intend.
Consider the following code.:
class ListManipulate(val list: List<Char>, val blockCount: Int) {
var result: List<List<Char>> = emptyList()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result = result.plusElement(constructSequence(sequence))
return
}
for (i in start..list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> =
List(sequence.size, { i -> list[sequence[i]] })
}
PS: I also took the liberty to update your constructSequence() to something more concise.
Btw: += uses addAll internally.
/**
* Returns a list containing all elements of the original collection and then all elements of the given [elements] collection.
*/
public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> {
if (elements is Collection) {
val result = ArrayList<T>(this.size + elements.size)
result.addAll(this)
result.addAll(elements)
return result
} else {
val result = ArrayList<T>(this)
result.addAll(elements)
return result
}
}
Side note: you can also do:
result.toMutableList().add(constructSequence(sequence))
It is fine to return a MutableList, the only difference really is that the List interface doesnt have the manipulation methods. Internally both are represented by an ArrayList
#SinceKotlin("1.1")
#kotlin.internal.InlineOnly
public inline fun <T> List(size: Int, init: (index: Int) -> T): List<T> = MutableList(size, init)