How to create a 2darray in kotlin of objects? [duplicate] - kotlin

This question already has answers here:
2D Array in Kotlin
(11 answers)
Closed 1 year ago.
I am genuinely shocked on how hard it is to find a good explanation on how to create a 2d array in Kotlin for an object.
These are my attempts from what I have found neither here on stack and online neither work, why? how do I create a 2d array of objects not built into Kotlin!!!
var matrix : Array<Array<myObject?>> = null
//var arr2D = Array(10) { Array(10) { myObject(this) } }
for (i in 0 until 9) {
for (j in 0 until 9) {
matrix[i][j] = myObject(this)
}
}
It says "null can not be a value of a non-null type" so I guess I have to use an arrayofnulls(), but cannot find a source can someone help me or give me a source?

This is how you create a 2D Array in Kotlin with a user made object. ArrayofNulls allows you to set all indexes in the array to null and then just initialize them later with a for loop!
val matrix = Array(10) {
arrayOfNulls<myObject?>(
10
)
}

Related

Slice() nested for loop values i and j Kotlin

I'm wanting to slice a range which I can do in Javascfript but am struggling in kotlin.
my current code is:
internal class blah {
fun longestPalindrome(s: String): String {
var longestP = ""
for (i in 0..s.length) {
for (j in 1..s.length) {
var subS = s.slice(i, j)
if (subS === subS.split("").reversed().joinToString("") && subS.length > longestP.length) {
longestP = subS
}
}
}
return longestP
}
and the error I get is:
Type mismatch.
Required:
IntRange
Found:
Int
Is there a way around this keeping most of the code I have?
As the error message says, slice wants an IntRange, not two Ints. So, pass it a range:
var subS = s.slice(i..j)
By the way, there are some bugs in your code:
You need to iterate up to the length minus 1 since the range starts at 0. But the easier way is to grab the indices range directly: for (i in s.indices)
I assume j should be i or bigger, not 1 or bigger, or you'll be checking some inverted Strings redundantly. It should look like for (j in i until s.length).
You need to use == instead of ===. The second operator is for referential equality, which will always be false for two computed Strings, even if they are identical.
I know this is probably just practice, but even with the above fixes, this code will fail if the String contains any multi-code-unit code points or any grapheme clusters. The proper way to do this would be by turning the String into a list of grapheme clusters and then performing the algorithm, but this is fairly complicated and should probably rely on some String processing code library.
class Solution {
fun longestPalindrome(s: String): String {
var longestPal = ""
for (i in 0 until s.length) {
for (j in i + 1..s.length) {
val substring = s.substring(i, j)
if (substring == substring.reversed() && substring.length > longestPal.length) {
longestPal = substring
}
}
}
return longestPal
}
}
This code is now functioning but unfortunately is not optimized enough to get through all test cases.

How to properly iterate over arrays in kotlin

I am currently learning kotlin and therefore following the kotlin track on exercism. The following exercise required me to calculate the Hamming difference between two Strings (so basically just counting the number of differences).
I got to the solution with the following code:
object Hamming {
fun compute(dnaOne: String, dnaTwo: String): Int {
if (dnaOne.length != dnaTwo.length) throw IllegalArgumentException("left and right strands must be of equal length.")
var counter = 0
for ((index, letter) in dnaOne.toCharArray().withIndex()) {
if (letter != dnaTwo.toCharArray()[index]) {
counter++
}
}
return counter
}
}
however, in the beginning I tried to do dnaOne.split("").withIndex() instead of dnaOne.toCharArray().withIndex() which did not work, it would literally stop after the first iteration and the following example
Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT") would return 1 instead of the correct integer 9 (which only gets returned when using toCharArray)
I would appreciate any explanation
I was able to simplify this by using the built-in CharSequence.zip function because StringimplementsCharSequence` in Kotlin.
According to the documentation for zip:
Returns a list of pairs built from the characters of this and the [other] char sequences with the same index
The returned list has length of the shortest char sequence.
Which means we will get a List<Pair<Char,Char>> back (a list of pairs of letters in the same positions). Now that we have this, we can use Iterable.count to determine how many of them are different.
I implemented this as an extension function on String rather than in an object:
fun String.hamming(other: String): Int =
if(this.length != other.length) {
throw IllegalArgumentException("String lengths must match")
} else {
this.zip(other).count { it.first != it.second }
}
This also becomes a single expression now.
And to call this:
val ham = "GGACGGATTCTG".hamming("AGGACGGATTCT")
println("Hamming distance: $ham")

Operator call corresponds to a dot-qualified call which is not allowed on a nullable receiver error [duplicate]

This question already has answers here:
Kotlin Map with non null values
(5 answers)
Closed 4 years ago.
This code doesn't compile:
val map = mutableMapOf<Int, Int>()
ar.forEach{
if(!map.containsKey(it)) {
map[it] = 1
} else {
map[it] = map[it] + 1
}
}
This is the compilation error:
Operator call corresponds to a dot-qualified call 'map[it].plus(1)'
which is not allowed on a nullable receiver 'map[it]'.
Since the mutableMap I created is not having nullable parameters, I am wondering why do I need to add not null checks later on? This code passes:
else map[it] = map[it]!! + 1
It's because map[it] might return null if there's no entry in the map corresponding to that key. Even though you checked by calling containsKey on the line before, that doesn't guarantee that when you call map[it] you'll get a value back, as another thread might update the map's contents in between those two calls.

From Option to iterator [duplicate]

This question already has answers here:
How to convert an Option<T> to an iterator of zero or one element?
(1 answer)
How can I iterate on an Option<Vec<_>>?
(4 answers)
Closed 4 years ago.
I have a function which consumes an iterator:
fn func<T: iter::Iterator<Item = char>>(i: T) {
//...
}
I need to write a function whose input is an Option<char> (type char is not important here, just for illustrative purpose), and depends on the value of input, it should create an empty or an once iterator. My solution is:
use std::iter;
fn option_iter(input: Option<char>) {
let i: Box<iter::Iterator<Item = char>> = if let Some(input) = input {
Box::new(iter::once(input))
} else {
Box::new(iter::empty())
};
}
I find this ugly because of type erasure by Box. I cannot use:
let i = if let Some(input) = input {
iter::once(input)
} else {
iter::empty()
};
func(i);
because the compiler complains the types of two branches are different. Is there any method which does not use Box for this situation?
Option has an iter method that does what you want.

Differences in for-loops. Swift v.s. Objective-C [duplicate]

This question already has answers here:
Removing from array during enumeration in Swift?
(9 answers)
Closed 6 years ago.
In this loop we have the potential to reduce the number of items in the loop while processing it. This code works fine in Obj-C, but the Swift loops don't get the message that an item has been removed and end up overflowing the array.
In Objective-C, we had:
for(int i = 4; i < staticBlocks.count; i++)
{
PlayerSprite* spr = [staticBlocks objectAtIndex:i];
[spr setPosition:CGPointMake(spr.position.x, spr.position.y-1)];
if(spr.position.y < -1000)
{
[staticBlocks removeObject:spr];
[spr removeFromParent];
}
if(spr.blockTypeIndex == Block_Type_Power_Up)
{
[spr update];
}
}
In Swift I know of these options:
//for i in 4.stride(to: staticBlocks.count, by: 1){ //crashes
//for i in 4..<staticBlocks.count{ //crashes
for var i = 4; i < staticBlocks.count; i += 1 { //works, but is deprecated
let spr = staticBlocks.objectAtIndex(i) as! PlayerSprite
spr.position = CGPointMake(spr.position.x, spr.position.y-1)
if(spr.position.y < -1000)
{
staticBlocks.removeObject(spr)
spr.removeFromParent()
//break
}
if(spr.blockTypeIndex == k.BlockType.PowerUp)
{
spr.update()
}
}
In this specific case, it really isn't a problem for me to use a break statement (which is currently commented out) to kill the loop and prevent the crash, but it doesn't seem like the proper fix. I assume there will come a time when I need to know how do do this correctly. Is there a non deprecated way to do a for loop, one which processes the count each pass?
A related, unanswered question.
Is the for loop condition evalutaed each loop in swift?
I don't know how to link to a specific answer, but this code did what I needed. Marking as duplicate now.
Removing from array during enumeration in Swift?
var a = [1,2,3,4,5,6]
for (i,num) in a.enumerate().reverse() {
a.removeAtIndex(i)
}
This is because in Swift you cannot remove items from an array while you are iterating over it.
From this question Removing from array during enumeration in Swift?
you can see that you should be using the filter function instead of using a for loop.
For example, don't do this:
for (index, aString: String) in enumerate(array) {
//Some of the strings...
array.removeAtIndex(index)
}
Do something like this:
var theStrings = ["foo", "bar", "zxy"]
// Filter only strings that begins with "b"
theStrings = theStrings.filter { $0.hasPrefix("b") }
(Code example from this answer)
Additionally, it should be noted that filter won't update the array, it will return a new one. You can set your array to be equal to that array afterwards.
An additional way to solve the issue, from the same question is to do this:
var a = [1,2,3,4,5,6]
for (i,num) in a.enumerate().reverse() {
a.removeAtIndex(i)
}
print(a)