how return array from function in Kotlin - kotlin

Hello i'm trying to return array from my function but i got this in result:
[Ljava.lang.String;#1be6f5c3
but function output correctly, for example:
12, 54, 65
fun main() {
val array = arrayOf(loopForNumbers(n))
println(array)
}
fun loopForNumbers(n: Int): String {
val array = IntArray(n)
var i = 0
while (i < n) {
println("Input number № ${i + 1}")
array[i] = readLine()?.toIntOrNull() ?: continue
i++
}
println(array.joinToString())
return array.joinToString()
}

You got confused I think, it's better to return the array as-is and then format it
fun main() {
val array = loopForNumbers(n)
println(array.joinToString())
}
fun loopForNumbers(n: Int): IntArray {
val array = IntArray(n)
var i = 0
while (i < n) {
println("Введите число № ${i + 1}")
array[i] = readLine()?.toIntOrNull() ?: continue
i++
}
println(array.joinToString())
return array
}

but function output correctly, for example:
12, 54, 65
val array = arrayOf(loopForNumbers(n))
This creates a single-element array containing (in this case) the string "12, 54, 65".
println(array)
println calls toString() on its argument, and for an array toString is pretty useless because it doesn't include the array contents; [Ljava.lang.String;#1be6f5c3 is a String array and [I#1be6f5c3 is an Int array, but the part after # just lets you see if two arrays are the same. Instead try
println(array.joinToString())
see https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/join-to-string.html for documentation and optional parameters.

Related

Proper use of Number class in Kotlin

Can anyone help me implement these methods in Kotlin?
I want to find min, max elements of array of numbers and also sort array in ascending order. Here is a code
class DataArray<Number>(vararg numbers: Number) {
private val array = mutableListOf<Number>(*numbers)
fun getMin() {
return array.minByOrNull { it! } //doesn't work
}
fun getMax() = array.max() //doesn't work
fun sort() = array.sort() //doesn't work
private fun <E> MutableList<E>.max(): Any { //was created to use in function above, but resulted in stack overflow
return this.max()
}
private fun <E> MutableList<E>.sort(): Any { //was created to use in function above, but resulted in stack overflow
return this.sort()
}
override fun toString(): String {
var str = ""
for(i in array)
str += "$i "
return str
}
}
fun main() {
val arr = DataArray(2, 5, 2, 6, 9, -3, 56, 16, 72, 8)
println(arr.getMax())
println(arr.getMin())
println(arr.sort())
print(arr)
}
Note that the word Number here declares a generic parameter called Number. It does not refer to kotlin.Number. You might have intended it to declare a generic parameter with a bound of Number instead, in which case you should have written:
class DataArray<T: Number>(vararg numbers: T) {
...
}
But even if you did, it still wouldn't work as Numbers are not comparable.
You would have to further constrain T to Comparable<T>:
class DataArray<T: Number>(vararg numbers: T) where T: Comparable<T> {
Then you can do:
fun getMin() = array.minOrNull()
fun getMax() = array.maxOrNull()
fun sort() = array.sort()
Extension functions on MutableList are unnecessary.
(Note that technically, the T: Number constraint is also unnecessary if you just want to use minOrNull, maxOrNull, and sort. I'm assuming you are planning on using one of the methods in kotlin.Number. Otherwise you can delete that constraint.)
You seem to be trying to implement your own MutableList by delegation. Keep in mind that you can easily do this using by:
class DataArray<T: Number>(
vararg numbers: T
) : MutableList<T> by mutableListOf(*numbers) {
override fun toString(): String {
var str = ""
for(i in this) // rather than "array", use "this"
str += "$i "
return str
}
}

How to change the characters in a string in kotlin

I am trying to change the character in a string to some other character.
Here is my code
fun main(args: Array<String>) {
var str: String = "H...H"
for(i in 0..str.length-1) {
if( str[i] == '.')
str[i] = 'B'
}
println(ans)
}
But this produces the error:
jdoodle.kt:20:16: error: no set method providing array access
str[i] = 'B'
But the following code works fine:
fun main(args: Array<String>) {
var str: String = "H...H"
var ans : String = ""
for(i in 0..str.length-1) {
if( str[i] == 'H')
ans += str[i]
else if( str[i] == '.')
ans += 'B'
}
println(ans)
}
I just want to change all the ..... in the string to B.
Like "H...H" to "HBBBH"
Why is the first code not working?
The first example does not work because Strings in kotlin are immutable and you cannot change characters. Instead, you have to create a new String, like your second example (which, in fact, creates a new String for each time through the loop).
Kotlin has a replace function for you:
fun main() {
val input = "H...H"
val output = input.replace('.', 'B')
println(output) // Prints "HBBBH"
}

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)

Idiomatic way to generate a random alphanumeric string in Kotlin

I can generate a random sequence of numbers in a certain range like the following:
fun ClosedRange<Int>.random() = Random().nextInt(endInclusive - start) + start
fun generateRandomNumberList(len: Int, low: Int = 0, high: Int = 255): List<Int> {
(0..len-1).map {
(low..high).random()
}.toList()
}
Then I'll have to extend List with:
fun List<Char>.random() = this[Random().nextInt(this.size)]
Then I can do:
fun generateRandomString(len: Int = 15): String{
val alphanumerics = CharArray(26) { it -> (it + 97).toChar() }.toSet()
.union(CharArray(9) { it -> (it + 48).toChar() }.toSet())
return (0..len-1).map {
alphanumerics.toList().random()
}.joinToString("")
}
But maybe there's a better way?
Since Kotlin 1.3 you can do this:
fun getRandomString(length: Int) : String {
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
return (1..length)
.map { allowedChars.random() }
.joinToString("")
}
Lazy folks would just do
java.util.UUID.randomUUID().toString()
You can not restrict the character range here, but I guess it's fine in many situations anyway.
Assuming you have a specific set of source characters (source in this snippet), you could do this:
val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
java.util.Random().ints(outputStrLength, 0, source.length)
.asSequence()
.map(source::get)
.joinToString("")
Which gives strings like "LYANFGNPNI" for outputStrLength = 10.
The two important bits are
Random().ints(length, minValue, maxValue) which produces a stream of length random numbers each from minValue to maxValue-1, and
asSequence() which converts the not-massively-useful IntStream into a much-more-useful Sequence<Int>.
Using Collection.random() from Kotlin 1.3:
// Descriptive alphabet using three CharRange objects, concatenated
val alphabet: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
// Build list from 20 random samples from the alphabet,
// and convert it to a string using "" as element separator
val randomString: String = List(20) { alphabet.random() }.joinToString("")
Without JDK8:
fun ClosedRange<Char>.randomString(length: Int) =
(1..length)
.map { (Random().nextInt(endInclusive.toInt() - start.toInt()) + start.toInt()).toChar() }
.joinToString("")
usage:
('a'..'z').randomString(6)
To define it for a defined length:
val randomString = UUID.randomUUID().toString().substring(0,15)
where 15 is the number of characters
('A'..'z').map { it }.shuffled().subList(0, 4).joinToString("")
Using Kotlin 1.3:
This method uses an input of your desired string length desiredStrLength as an Integer and returns a random alphanumeric String of your desired string length.
fun randomAlphaNumericString(desiredStrLength: Int): String {
val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
return (1..desiredStrLength)
.map{ kotlin.random.Random.nextInt(0, charPool.size) }
.map(charPool::get)
.joinToString("")
}
If you prefer unknown length of alphanumeric (or at least a decently long string length like 36 in my example below), this method can be used:
fun randomAlphanumericString(): String {
val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
val outputStrLength = (1..36).shuffled().first()
return (1..outputStrLength)
.map{ kotlin.random.Random.nextInt(0, charPool.size) }
.map(charPool::get)
.joinToString("")
}
Or use coroutine API for the true Kotlin spirit:
buildSequence { val r = Random(); while(true) yield(r.nextInt(24)) }
.take(10)
.map{(it+ 65).toChar()}
.joinToString("")
Building off the answer from Paul Hicks, I wanted a custom string as input. In my case, upper and lower-case alphanumeric characters. Random().ints(...) also wasn't working for me, as it required an API level of 24 on Android to use it.
This is how I'm doing it with Kotlin's Random abstract class:
import kotlin.random.Random
object IdHelper {
private val ALPHA_NUMERIC = ('0'..'9') + ('A'..'Z') + ('a'..'z')
private const val LENGTH = 20
fun generateId(): String {
return List(LENGTH) { Random.nextInt(0, ALPHA_NUMERIC.size) }
.map { ALPHA_NUMERIC[it] }
.joinToString(separator = "")
}
}
The process and how this works is similar to a lot of the other answers already posted here:
Generate a list of numbers of length LENGTH that correspond to the index values of the source string, which in this case is ALPHA_NUMERIC
Map those numbers to the source string, converting each numeric index to the character value
Convert the resulting list of characters to a string, joining them with the empty string as the separator character.
Return the resulting string.
Usage is easy, just call it like a static function: IdHelper.generateId()
I use the following code to generate random words and sentences.
val alphabet: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
val randomWord: String = List((1..10).random()) { alphabet.random() }.joinToString("")
val randomSentence: String = (1..(1..10).random()).joinToString(" ") { List((1..10).random()) { alphabet.random() }.joinToString("") }
the question is old already, but I think another great solution (should work since Kotlin 1.3) would be the following:
// Just a simpler way to create a List of characters, as seen in other answers
// You can achieve the same effect by declaring it as a String "ABCDEFG...56789"
val alphanumeric = ('A'..'Z') + ('a'..'z') + ('0'..'9')
fun generateAlphanumericString(length: Int) : String {
// The buildString function will create a StringBuilder
return buildString {
// We will repeat length times and will append a random character each time
// This roughly matches how you would do it in plain Java
repeat(length) { append(alphanumeric.random()) }
}
}
fun randomAlphaNumericString(#IntRange(from = 1, to = 62) lenght: Int): String {
val alphaNumeric = ('a'..'z') + ('A'..'Z') + ('0'..'9')
return alphaNumeric.shuffled().take(lenght).joinToString("")
}
Building on Fabb111's answer:
fun randomString(length: Int): String =
buildString {
repeat(length) {
append((0 until 36).random().toString(36))
}
}
Numbers can be converted to a different base using the Int.toString(Int).
Base 36 is the numeral system that contains all alphanumeric characters
You can use RandomStringUtils.randomAlphanumeric(min: Int, max: Int) -> String from apache-commons-lang3
Here's a cryptographically secure version of it, or so I believe:
fun randomString(len: Int): String {
val random = SecureRandom()
val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray()
return (1..len).map { chars[random.nextInt(chars.size)] }.joinToString("")
}
I used the most voted answer, but after using it for a while I discovered a big problem, since the random strings weren't that random.
I had to modify the generation of the random character, since if I only left allowedChars.random() it always generated the same strings, and I couldn't find why. I was reading that because random() was called very quickly, but I don't know how it works when calling it on the list of numbers.
fun getRandomString(): String {
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
var string = ""
for (i in (1..20)) {
string += allowedChars[(Math.random() * (allowedChars.size - 1)).roundToInt()]
}
return string
}
// initialise at top
companion object {
private const val allowedCharacters = "0123456789QWERTYUIOPASDFGHJKLZXCVBNM"
}
//pass size and get Random String Captcha
fun getRandomCaptcha(sizeOfRandomCaptcha: Int): String {
val random = Random()
val sb = StringBuilder(sizeOfRandomCaptcha)
for (i in 0 until sizeOfRandomCaptcha)
sb.append(allowedCharacters[random.nextInt(allowedCharacters.length)])
return sb.toString()
}
Here's a simple function that uses newer Kotlin stdlib functions:
fun randomString(length: Int): String =
CharArray(length) { validChars.random() }.concatToString()
val validChars: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9'),
This uses:
a collection constructor with a initializer function
CharArray(length) { i -> /* provide a value for element i */ }
This is a one-liner for creating a CharArray and initializing each value using a lambda, It accepts a length, so the CharArray will be initialized with the correct size.
The Collection<>.random() extension function, that will pick a random character. This can be seeded if desired.
validChars.random()
The initialized CharArray is converted to a string using concatToString(), which was released in version 1.4.
The best way I think:
fun generateID(size: Int): String {
val source = "A1BCDEF4G0H8IJKLM7NOPQ3RST9UVWX52YZab1cd60ef2ghij3klmn49opq5rst6uvw7xyz8"
return (source).map { it }.shuffled().subList(0, size).joinToString("")
}

Reading multiple ints from the same line in Kotlin?

I am doing the 30 Days of Code in Kotlin on Hackerrank and I am stuck at Day 7.
How do you read multiple integers on a single line?
How is it added to an array and displayed in reverse?
I have solved it in Java but lack the syntax needed in Kotlin
Input:
4
1 4 3 2
My Code:
fun main(args: Array<String>) {
val n = readLine()!!.toInt()
var arr = Array(n)
for(i in 0 until n)
{
arr[i] = readLine()!!.toInt() //Not Working? nor does readLine()!!.split(' ').toInt()
}
for(item in arr.size - 1 downTo 0)
{
print("${item} ")
}
}
EDIT: question was updated from the original
The problem is the readLine() will read the entire line from stdin, so each time you call readLine() in the for loop it will result in a separate line being read each time.
One approach to this is to read the line, and then to split and map each value to an Int.
readLine()?.let {
val numOfValues = it.toInt()
println(numOfValues)
readLine()?.let { line ->
line.split(" ").map {
it.toInt()
}.reversed().forEach {
println(it)
}
}
}
If you want to store them in a list then you can follow this method
var items = readLine()!!.trim().split("\\s+".toRegex()).map (String::toInt)
println(items)
You can also store them in different variables like this way
var (a,b) = readLine()!!.trim().split("\\s+".toRegex()).map (String::toInt)
println(a+b)
You can also use the following code to item items splited and stored in array for a beginner approach
fun main(ags :Array<String>)
{
var item = readLine()!!.trim()
println(item[0])
}
Actually, you can refer to the official Kotlin tutorial: https://kotlinlang.org/docs/tutorials/competitive-programming.html
as mentioned in tutorial:
To make reading the input in competitive programming tasks like this more concise, you can have the following list of helper input-reading functions:
private fun readLn() = readLine()!! // string line
private fun readInt() = readLn().toInt() // single int
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints
for your case, you can try use as below:
fun main() {
val n = readInt()
val x = readInts()
for (j in x.reversed()) {
print(j); print(" ")
}
println()
}
private fun readLn() = readLine()!! // string line
private fun readInt() = readLn().toInt() // single int
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints