How to initialize and use charArray in Kotlin - kotlin

I have this code
var str : CharArray
var t =0
for (k in i..i+3) {
str[t++] = array[k][j]
and it says str must be initialized, i don't know how to initialize.
I tried to initialize like this, but it says type mismatch,
var array: Array<CharArray> = arrayOf("India");
Type inference failed. Expected type mismatch:
required:
Array
found:
Array

You can initialize it this way:
var str : CharArray = CharArray(3) //if you know size
var str : CharArray = charArrayOf() //creates empty array
var str : CharArray? = null //makes your array nullable
Or you can use lateinit for initializing later

There are many ways to initialize arrays in Kotlin. The easiest, if all values are the same (here I'm using blanks), is this:
var chars = CharArray(26) { ' ' }
If you have a specific set of characters (here I made it a constant), I found this to be an easy way:
val CHARS = "abcdefghijklmnopqrstuvwxyz".toCharArray()
If you want to copy one to another (clone), you can do this:
val array2 = CharArray(array.size) { i -> array[i] }
In the example you gave above, you're trying to initialize an array of CharArray. Not sure if that's what you really want, but you can do it this way (I have an array of 25 items, each of which is an array with 5 blanks):
var array2D = Array<CharArray>(25) { CharArray(5) { ' ' } }

You have declared a variable of type CharArray, but haven't assigned it with any instance.
Before you can set elements of that CharArray, you have to create an instance of CharArray. It looks like you know the size of that array in advance, then you can use the following array constructor:
// creates an instance of CharArray of 4 elements, filled with \u0000 chars
val str = CharArray(4)
// after that you can set elements in the array
Bonus point: if you have a function that can provide an array element value given its index you can use the similar constructor to create instance and initialized its elements at once:
val str = CharArray(4) { index ->
array[i + index][j]
}

I found this question interesting and I wanna add my answer since i was solving similar leetcode problem;
var charArray: CharArray = charArrayOf('I', 'n', 'd', 'i', 'a')
var array: Array<CharArray> = arrayOf(
charArrayOf('I', 'n', 'd', 'i', 'a'),
charArrayOf('P', 'h', 'i', 'l', 'i', 'p', 'p', 'i', 'n', 'e', 's'),
)
I hope this help someone since i was just transitioning from Java to Kotlin ;)

If you declare your CharArray as it, you must initialize it immediately. Otherwise you can specify that you will initialized it later with the property lateinit, or you can declare your variable as a CharArray and set it to null, or you can use a
var str : CharArray? = null
var lateinit str: CharArray

it says str must be initialized. The problem is that you did not completely define the structure of the char array you intend to create. The CharArray requires knowing the actual length or size of the array you're creating. So in this note, you need to initialize it before trying to populate it. my code snippet is down
.....Your code still has some issues with it.
var str : CharArray = CharArray(9)
var t = 0
for (k in 1..9) {
str[t] = k
}
The output::: values from 1 to 30 will be stored in the str character array

Related

How would I map a list of items to the arguments of another function?

I am trying to figure out the best way to map my sorted map to the arguments of another function. This is an example of what I have.
data class ValueDescription (val length: Int, val count: Int)
// Now I am trying to map to a variable that looks like this
// This variable cannot be changed, I have to return this variable in this format
// The output will be a list of ValueDescriptions with a length and count for each entry of the map I have
// I will add the results of myValues to a mutable list later
val myValues = ValueDescription(_length here__, __count here__)
I have a sorted map that I want to map to my values
// The map will look like this
// Where both Ints hold the lengths and counts
// For example I would have the length of 7 to count of 8
val out = Map<Int, Int>
How can I take the values in my sorted map and place them into the variable myValues?
I tried to map by looping through my map with the forEach method and doing something like
out.map{it.key to myValues.ValueDescription.length}
but this doesn't seem to work.
I'm not sure I completely understood the question. If I got it correctly, your input is the Map<Int, Int> and you want to transform it to a List<ValueDescription>.
You can definitely use the map function for this:
val inputMap: Map<Int, Int> = TODO("provide the initial map here")
val myValues = inputMap.map { (l, c) -> ValueDescription(l, c) }
The map function here iterates over the entries of the map, and transforms each of them into a value of type ValueDescription by calling our lambda (the part between braces { ... }).
Each entry of the map here contains a key (the length) and a value (the count). Instead of using it.key and it.value, you can also use parentheses like I did here with (l, c) to destructure the entry into its 2 parts and give them names like l and c. The above is equivalent to:
val myValues = inputMap.map { ValueDescription(it.key, it.value) }

What is the function of the * operation in Kotlin?

The Code A is from the offical sample project.
I don't understand what val tasks = remember { mutableStateListOf(*allTasks) } mean, could you tell me ?
BTW, Android Studio give me some information, you can see Image A
Code A
#Composable
fun Home() {
// String resources.
val allTasks = stringArrayResource(R.array.tasks)
val allTopics = stringArrayResource(R.array.topics).toList()
// The currently selected tab.
var tabPage by remember { mutableStateOf(TabPage.Home) }
// True if the whether data is currently loading.
var weatherLoading by remember { mutableStateOf(false) }
// Holds all the tasks currently shown on the task list.
val tasks = remember { mutableStateListOf(*allTasks) }
...
}
Image A
From the documentation of varargs:
When you call a vararg -function, you can pass arguments individually, for example asList(1, 2, 3). If you already have an array and want to pass its contents to the function, use the spread operator (prefix the array with *):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
As you see, it expands an array to multiple values for use in a vararg. If you havd an array containing the elements 1, 2, 3, you can pass *yourArray to a method that is equivalent to yourMethod(1,2,3).
In Kotlin * is the Spread Operator.
From docs :
When you call a vararg -function, you can pass arguments individually, for example asList(1, 2, 3). If you already have an array and want to pass its contents to the function, use the spread operator (prefix the array with *):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
In this case tasks will contain the list of strings from R.array.tasks

Kotlin For loop start from a given index

I want to start a For loop from a given index
in Java you can easily write
for (int i = startingIndex; i < items.size(); i++)
how to to do that in Kotlin?
I know how to write a for loop in Kotlin
my example
I want to iterate over an array of strings but the start position is 3, not iterating over a Range the iteration will be over a collection of items
For iterating from the start item till the last, you can use something like this:
for (i in startingIndex until items.size) {
//apply your logic
}
Another option is to drop first n elements and use forEach from there:
val l = listOf(1, 2, 3, 4)
l.drop(1).forEach { println(it) } // prints "2, 3, 4"
Instead of iterating over the items in your array, you can iterate over the indices and access the array by index. Here's a simple example.
val otherStrings = arrayOf("a", "b", "c", "d", "e")
for (i in 3..otherStrings.size-1)
println(otherStrings[i])
This iterates from starting index 3 to the last index (which is size - 1)
If the function is repeated several times you could do this:
Create an extension function
List<String>.startByIndex(startingIndex : Int){
for(index in startingIndex until this.size){
//apply common logic
}
}
call the extension function from your string list
var startIndex : Int = 3 // example
items.startByIndex(startIndex)
P.S. : If, for example, the extension function must always return a string as output, you have to change everything like this:
List<String>.startByIndex(startingIndex : Int) : String {
for(index in startingIndex until this.size){
var result : String
//apply common logic and instantiate var result
return result
}
}
var startIndex : Int = 3 // example
var result : String = items.startByIndex(startIndex)

deal with arrays of Kotlin with Long variables

I have a question about Kotlin.
I tried two versions of Kotlin, 1.0.0 and 1.2.6.
Using Kotlin, we can initialize an array and access to its element like this.
val n: Int = 10
val arr = Array(n, { it } )
val i: Int = 0
println(arr[i])
However, I got an error with this code.
val n: Long = 10
val arr = Array(n, { it } )
val i: Long = 0
println(arr[i])
It seems that it is an only way to cast Long to Int in order to compile this code.
val n: Long = 10
val arr = Array(n.toInt(), { it } )
val i: Long = 0
println(arr[i.toInt()])
However, it seems too redundant to me, but I couldn't find any solutions. So my question is
Is there any way to initialize arrays and access elements with a Long
variable?
Does Kotlin have any reasons that Long variable should not be accepted here?
Kotlin comes with longArrayOf(1, 2, 3) which will create an array for you which contains Longs.
Note that what you are trying to do with println(arr[i]) is getting a Long value out of arr, but the indexing of arrays is done with Ints. It will never work with Longs:
/**
* Returns the array element at the given [index].
* This method can be called using the index operator.
*/
public operator fun get(index: Int): Long
If you want to initialize an array of longs of the given length, you can use the same top-level Array function:
val n = 10 // n is Int
val arrayOfLongs = Array(n) { it.toLong() } // Array of 10 longs
Here the number n is Int and the initializer function converts the integer index it of an element being initialized to Long, therefore we get an array of longs as the result.
Or you can use another similar function to create a specialized LongArray:
val longArray = LongArray(n) { it.toLong() } // LongArray of 10 longs
Both arrays store longs, but the latter does it more compactly.

How can I tell Kotlin that an array or collection cannot contain nulls?

If I create an array, then fill it, Kotlin believes that there may be nulls in the array, and forces me to account for this
val strings = arrayOfNulls<String>(10000)
strings.fill("hello")
val upper = strings.map { it!!.toUpperCase() } // requires it!!
val lower = upper.map { it.toLowerCase() } // doesn't require !!
Creating a filled array doesn't have this problem
val strings = Array(10000, {"string"})
val upper = strings.map { it.toUpperCase() } // doesn't require !!
How can I tell the compiler that the result of strings.fill("hello") is an array of NonNull?
A rule of thumb: if in doubts, specify the types explicitly (there is a special refactoring for that):
val strings1: Array<String?> = arrayOfNulls<String>(10000)
val strings2: Array<String> = Array(10000, {"string"})
So you see that strings1 contains nullable items, while strings2 does not. That and only that determines how to work with these arrays:
// You can simply use nullability in you code:
strings2[0] = strings1[0]?.toUpperCase ?: "KOTLIN"
//Or you can ALWAYS cast the type, if you are confident:
val casted = strings1 as Array<String>
//But to be sure I'd transform the items of the array:
val asserted = strings1.map{it!!}
val defaults = strings1.map{it ?: "DEFAULT"}
Why the filled array works fine
The filled array infers the type of the array during the call from the lambda used as the second argument:
val strings = Array(10000, {"string"})
produces Array<String>
val strings = Array(10000, { it -> if (it % 2 == 0) "string" else null })
produces Array<String?>
Therefore changing the declaration to the left of the = that doesn't match the lambda does not do anything to help. If there is a conflict, there is an error.
How to make the arrayOfNulls work
For the arrayOfNulls problem, they type you specify to the call arrayOfNulls<String> is used in the function signature as generic type T and the function arrayOfNulls returns Array<T?> which means nullable. Nothing in your code changes that type. The fill method only sets values into the existing array.
To convert this nullable-element array to non-nullable-element list, use:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.filterNotNull()
val upper = strings.map { it.toUpperCase() } // no !! needed
Which is fine because your map call converts to a list anyway, so why not convert beforehand. Now depending on the size of the array this could be performant or not, the copy might be fast if in CPU cache. If it is large and no performant, you can make this lazy:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.asSequence().filterNotNull()
val upper = strings.map { it.toUpperCase() } // no !! needed
Or you can stay with arrays by doing a copy, but really this makes no sense because you undo it with the map:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings: Array<String> = Array(nullableStrings.size, { idx -> nullableStrings[idx]!! })
Arrays really are not that common in Java or Kotlin code (JetBrains studied the statistics) unless the code is doing really low level optimization. It could be better to use lists.
Given that you might end up with lists anyway, maybe start there too and give up the array.
val nullableStrings = listOf("a","b",null,"c",null,"d")
val strings = nullableStrings.filterNotNull()
But, if you can't stop the quest to use arrays, and really must cast one without a copy...
You can always write a function that does two things: First, check that all values are not null, and if so then return the array that is cast as not null. This is a bit hacky, but is safe only because the difference is nullability.
First, create an extension function on Array<T?>:
fun <T: Any> Array<T?>.asNotNull(): Array<T> {
if (this.any { it == null }) {
throw IllegalStateException("Cannot cast an array that contains null")
}
#Suppress("CAST_NEVER_SUCCEEDS")
return this as Array<T>
}
Then use this function new function to do the conversion (element checked as not null cast):
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.asNotNull() // magic!
val upperStrings = strings.map { it.toUpperCase() } // no error
But I feel dirty even talking about this last option.
There is no way to tell this to the compiler. The type of the variable is determined when it is declared. In this case, the variable is declared as an array that can contain nulls.
The fill() method does not declare a new variable, it only modifies the contents of an existing one, so it cannot cause the variable type to change.