Kotlin spread operator behaviour on chars array - kotlin

I have been using Kotlin for some time now, but I just found out that when I would like to use spread operator on the array of chars and pass it to the split function, it does not work.
fun main() {
val strings = arrayOf("one", "two")
val stringSplit = "".split("one", "two")
val stringsSplit = "".split(*strings)
val chars = arrayOf('1', '2')
val charSplit = "".split('1', '2')
val charsSplit = "".split(*chars) // this is not possible
}
produces following error (same during the build and same in the official try kotlin repl)
Am I doing something wrong?

This happens because in Kotlin Array<Char> is equal to Character[] in Java, not to char[] in Java.
To use the spread operator on an array of characters and pass it to a vararg Char parameter, you need to use CharArray which is equal to char[] in Java.
fun main() {
val strings = arrayOf("one", "two")
val stringSplit = "".split("one", "two")
val stringsSplit = "".split(*strings)
val chars = charArrayOf('1', '2')
val charSplit = "".split('1', '2')
val charsSplit = "".split(*chars) // this is not possible
}

Related

keeping track of injected variables when using string interpolation in kotlin

I'm looking for a way to keep track of variables used when doing a string interpolation without parsing the string. For example, if I have a string:
val expStr = "${var1} some other useless text ${var2}"
I want to be able to identify the order of the variables used, again without parsing the string. In this case [var1, var2] would be an expected output. So far I've thought of defining a class where I pass it all of the variables. Then reference said variables through the class function grab.
val wrapper = ContainerClass(var1, var2)
val expStr = "${wrapper.grab(var1)} some other useless text ${wrapper.grab(var2)}"
inside ContainerClass is a array, each time a variable is referenced it is added to the array and outputted through getReferenceCalls
val whatIWant = wrapper.getReferenceCalls() // [var1, var2]
This works great until I introduce the injection of strings into strings.
val wrapper = ContainerClass(var1, var2, var3)
val snippet = "${wrapper.grab(var1)} some other useless text ${wrapper.grab(var2)}"
val expStr = "${wrapper.grab(var3)} ${snippet}"
val notWhatIWant = wrapper.getReferenceCalls() // [var1, var2, var3]
Here, I want to identify the order of the injected variables in the final expStr ie. [var3, var1, var2]. My question is, is this possible without parsing expStr? I did also think of a not so elegant solution of allowing my class to define any given "snippet" and the class identifies the variables referenced in the snippet. This works but becomes convoluted fast. What I really need is an eligant solution...if it exists.
I have implemented a "ContainerClass" to achieve your goal. I uses String.format instead of string templates so that I don't need prior information of the input.
class StringNode(private val format: String, vararg args : Any) {
private val argv = args
override fun toString() : String = String.format(format,*argv)
fun getFlatArgs() : List<Any> = argv.flatMap {
if(it is StringNode){
it.getFlatArgs()
} else{
listOf(it)
}
}
}
Usage:
fun main(){
val sn1 = StringNode("1:%s 2:%s 3:%s","abc",123,"def")
println(sn1)
println(sn1.getFlatArgs())
val sn2 = StringNode("foo:%s bar:%s","foo",sn1);
println(sn2)
println(sn2.getFlatArgs())
val sn3 = StringNode("sn1:%s, sn2:%s",sn1,sn2);
println(sn3)
println(sn3.getFlatArgs())
}
Output:
1:abc 2:123 3:def
[abc, 123, def]
foo:foo bar:1:abc 2:123 3:def
[foo, abc, 123, def]
sn1:1:abc 2:123 3:def, sn2:foo:foo bar:1:abc 2:123 3:def
[abc, 123, def, foo, abc, 123, def]
val var1 = "abc"
val var2 = "def"
val list = mutableListOf<String>()
val expStr = "${var1.also { list.add(it) }} some other useless text ${var2.also { list.add(it) }}"
println(expStr) // Output: "abc some other useless text def"
println(list) // Output: [abc, def]
Or:
val var1 = "abc"
val var2 = "def"
val list = mutableListOf<String>()
fun String.addTo(list: MutableList<String>) = this.also { list.add(it) }
val expStr = "${var1.addTo(list)} some other useless text ${var2.addTo(list)}"
println(expStr) // Output: "abc some other useless text def"
println(list) // Output: [abc, def]

How to split operators and operands into two arrays?

I want to split this content into two seperate arrays numbers and operators in Kotlin.
The content is "2*5-6+7".
This is my code which doesnt work:
val arrnum = content.split("[-+*/]").toTypedArray()
val operator = content.split("[0123456789]").toTypedArray()
Maybe something like this, using partition:
val OPERATORS = setOf('*', '+', '-', '/')
fun main() {
val (operators, numbers) = "2*5-6+7".toList().partition { it in OPERATORS }
println(operators)
println(numbers)
}
Prints:
[2, 5, 6, 7]
[*, -, +]
If you want to use regular expressions you have to wrap them into Regex("[-+*/]")
The full example would look like this:
val arrnum = content.split(Regex("[-+*/]")).toTypedArray()
val op = content.split(Regex("[0123456789]")).toTypedArray()
Other things to note: "operator" is a keyword in Kotlin. You can simplify [0123456789] to [\d] (with double \ in Kotlin). The operator array will contain empty entries for what's left of of the two and right of the 7. You can filter them out like .filter { it.isNotBlank() }
Solution without regular expressions, but with mutability:
const val OPERATORS = "*+-/"
fun main() {
val s = "2*55-6+7"
val numbers = mutableListOf<Int>()
val operators = mutableListOf<Char>()
var prevIndex = 0
s.withIndex().forEach { (index, c) ->
if (c in OPERATORS) {
operators.add(c)
numbers.add(s.substring(prevIndex until index).toInt())
prevIndex = index + 1
}
}
numbers.add(s.substring(prevIndex).toInt())
println(operators)
println(numbers)
}
Solution without regular expressions in functional style:
const val OPERATORS = "*+-/"
fun main() {
val s = "2*55-6+7"
val operatorsIndexed = s.withIndex().filter { it.value in OPERATORS }
val operators = operatorsIndexed.map { it.value }
val numbers = listOf(-1, *operatorsIndexed.map { it.index }.toTypedArray(), s.length)
.windowed(2)
.map { (from, to) -> s.substring(from + 1 until to).toInt() }
println(operators)
println(numbers)
}

Kotlin/Native: How to convert cArrayPointer to Array

How can I convert cArrayPointer to a simple Array/List when using c-interop?
val myArray: Array<Int> = memScoped {
val cArray = allocArray<IntVar>(5)
fill(cArray)
cArray.toSimpleArray() <--- There is no such function
}
I'd recommend to make it somehow like this:
val myArray: Array<Int> = memScoped {
val length = 5 //cause I don't know how to get C-array size
val cArray = allocArray<IntVar>(length)
(0 until length).map { cArray[it] }.toTypedArray()
}
As one can see in the documentation, CArrayPointer is nothing but a typealias of CPointer. So, I suppose there can't be anadditional functionality, like one you desire.

Filter a substring in kotlin

In kotlin I'd like to filter a string and return a substring of only valid characters. Say we have valid characters,
valid = listOf('A', 'B', 'C')
How can I define a fcn in kotlin in the most succinct way to filter a string and only retain valid characters? For example,
'ABCDEBCA' --> 'ABCBCA'
'AEDC' --> 'AC'
Having trouble finding a canonical way to do this without resorting to using an array of string.
import kotlin.text.filter
class Test(){
val VALID = listOf("A", "B", "C")
fun filterString(expression: String): String{
expression.filter(x --> !VALID.contains(x)) #Doesn't work
}
}
The filter docs doesn't show any examples specifically for spring manipulation.
val VALID = setOf('A', 'B', 'C') // lookup in a set is O(1), whereas it's O(n) in a list. The set must contain Chars, not Strings
val expression = "ABCDEFEDCBA"
val filtered = expression.filter { VALID.contains(it) }
println(filtered)
// ABCCBA
Or
val VALID = setOf('A', 'B', 'C')
fun filterString(expression: String) = expression.filter { it in VALID }
fun main(args: Array<String>) {
val expression = "ABCDEFEDCBA"
val filtered = filterString(expression)
println(filtered)
// ABCCBA
}
In case you have a long set of chars you could join them in a String and convert it to a Set:
val VALID = "ABC".toSet()
fun filterString(expression: String) = expression.filter { it in VALID }
fun main(args: Array<String>) {
val expression = "ABCDEFEDCBA"
val filtered = filterString(expression)
println(filtered)
// ABCCBA
}

How to "prepend" a Char to a String in Kotlin

How in Kotlin can I prepend a Char to a String?
e.g.
fun main(args: Array<String>) {
val char = 'H'
val string = "ello World"
val appendingWorks = string + char //but not what I want...
//val prependingFails = char + string //no .plus(str:String) version
val prependingWorkaround1 = char.toString() + string
val prependingWorkaround2 = "" + char + string
val prependingWorkaround3 = String(charArray(char)) + string
}
When trying to call + (e.g. plus) on Char, there is no version that accepts a String on the right, so therefore 'H' + "ello World" doesn't compile
The first workaround might be good enough but it's a regression for me from what works in Java: String test = 'H' + "ello World"; (compiles fine...)
I also don't like the last workaround, at least in the java.lang.String I have a constructor that accepts a single char, or I can use java.lang.Character.toString(char c). Is there an elegant way in Kotlin to do so?
Was this discussed before (adding a plus(str:String) overload to the Char object?)
What about using string templates, like this:
val prepended = "$char$string"
As of kotlin 1.5, there is an extension plus operator function defined on Char, which can be used to concatenate a Char with given String. So you can do
val char = 'H'
val string = "ello World"
// Use the function call syntax
val result1 = char.plus(string)
// or use the operator syntax
val result2 = char + string
If you want to truly prepend a string using just a method call on that string, you can do the following:
val str = "ello World!"
println(str.let { 'H' + it })
This way can be useful if str was instead a large complicated chain of method calls:
val squares = ... // 10x10 array of square numbers
println(squares.joinToString("\n") {
it.joinToString(" ") { "%03d".format(it) }
}.let { "Squares:\n" + it })