How to create list in Kotlin? - kotlin

I tried these in Kotlin REPL
var listA = listOf(null ,null)
var listB = [null, null]
The first line works fine as expected. On displaying listA I get:
[null, null]
The second line throws the following error:
error: cannot use 'Nothing?' as reified type parameter
var listB = [null,null]
^
error: unsupported [Collection literals outside of annotations]
var listB = [null,null]
^
error: unsupported [Array<Nothing> in return type is illegal]
var listB = [null,null]
^
When I try the same with non null types,
i.e.
var listC = [1,2]
I get this error:
error: unsupported [Collection literals outside of annotations]
var listC = [1,2]
^
I'm new to Kotlin. Can someone please explain what is going on here?

From the Kotlin documentation on Collections:
Kotlin does not have dedicated syntax constructs for creating lists or sets. Use methods from the standard library, such as listOf(), mutableListOf(), setOf(), mutableSetOf().
There are no list literals currently for code outside of annotations.

As #Carcigenicate pointed out, there is not syntax for [null, null].
However, Kotlin does have some handy methods for handling lists and arrays.
Lists
listOf()
Creates a new read-only List.
listOfNotNull()
Basically the same as listOf(), but without null values. Even empty strings
are skipped.
arrayListOf()
Creates an ArrayList. This time you can modify (add/remove) elements.
mutableListOf()
Behaves like arrayListOf(). Actually, mutableListOf() internally uses ArrayLists. Read more
Arrays
arrayOf()
This creates an array, which is very different to most languages you know.
Instead of syntax structures like {1, 2, 3} or [1, 2, 3] you have functions
in Kotlin. You also get functions for typed array:
booleanArrayOf()
doubleArrayOf()
charArrayOf()
...
One exception are annotations, which explains your compiler error [Collection literals outside of annotations]:
#MyAnnotation(arguments = [1, 2, 3])
However, this could change in the future as discussed here.
While working with arrays, it is important to know the return types those functions are creating.
As an example:
Array<Int> is an Integer[] under the hood, while IntArray is a primitive int[] when targeting the JVM.

So for the case of mutable lists, you can declare an empty String one with: val list: MutableList<String> = mutableListOf(). If you wanted an immutable list then you could use val like so: val list: List<String> = listOf("x", "y", "z").
Also note, that you should consider your use case for using val or var. Mutability of a list pertains to values within the list itself, where as val and var are for the variable. You can reassign the list if you use var but not val (similar to final of Java)
For the sake of clarity, as an example, mutable lists can have elements added an removed after their initialisation, while immutable cannot.
Immutable Lists Docs
Mutable List Docs

You get [null, null] because that's how toString() happens to be defined in java.util.AbstractCollection and listOf creates a java.util.ArrayList which inherits this implementation.
The errors you get are because there is a place in Kotlin where this syntax happens to work: annotation parameters. So the parser understands it. But it creates arrays, not lists, and so your code wouldn't compile even if the syntax wasn't limited to annotations.

Yes this is not the correct syntax for creating List with Kotlin.
Here is an example of List and MutableList(with write operations) and some of the operations you can do on them:
List
val numbers = listOf("one", "two", "three", "four")
println("Number of elements: ${numbers.size}")
println("Third element: ${numbers.get(2)}")
println("Fourth element: ${numbers[3]}")
println("Index of element \"two\" ${numbers.indexOf("two")}")
MutableList
val numbers = mutableListOf(1, 2, 3, 4)
numbers.add(5)
numbers.removeAt(1)
numbers[0] = 0
numbers.shuffle()
println(numbers)

Related

How to initialize List< List<Int> > in Kotlin?

As per leetcode question here I am required to return List<List<Int>> type for Kotlin submission.
I tried using listOf() but unable to create.
My another guess was to use LinkedList of type List:
var result: List<List<Int>> = LinkedList<List<Int>>()
The intelliJ idea gives no warnings for the above declaration but add() is not available on result variable. Please let me know what I am doing wrong.
How should I initialize empty List<List<Int>> type in kotlin?
add is not available for List. It's available for MutableList. LinkedList is a MutableList, but you are upcasting it to a plain List by assigning it to a variable of type List.
If you need to work with a MutableList or LinkedList inside this function, you can do so by not declaring the type of the result variable so it will implicitly be a MutableList or LinkedList. When you return it from the function, it will be implicitly upcast at that time, when you no longer need the mutable features.
fun threeSum(nums: IntArray): List<List<Int>> {
val output = mutableListOf<MutableList<Int>>()
// logic
return output
}
or
fun threeSum(nums: IntArray): List<List<Int>> {
val output = LinkedList<LinkedList<Int>>()
// logic
return output
}
LinkedList is a specific type of MutableList that compared to the default MutableList (ArrayList) is heavier and slower at accessing specific elements in the middle, but faster at accessing elements at the start/end and faster at inserting or removing elements. You will most commonly just want to use mutableListOf to instantiate mutable lists.
you can use
var result: List<List<Int>> = listOf(listOf())
or
var result = listOf(listOf<Int>())

Adding char to List<Char> in kotlin

I am trying to create List<Char> from String in Kotlin but it seems there is no inbuilt function is provided by lib. Also casting will generate error. So here is what I am doing. Please let me know if I am missing something in question. (Or we can say converting string to List<Char> in Kotlin).
var stringVal = "ABC"
var genList:List<Char> = arrayListof()
var count = 0
while (stringVal.length == genList.size) {
// way to add stringVal to genList
count++
}
The answer given by #Moira is definitely the way to go here, I would accept it.
However, the question was about adding an element to a List<Char>, which isn't possible in Kotlin because a List is immutable and yours gets initialized as an empty one, so it will stay empty.
Use a MutableList<Char> and simply add single Chars to it if you need it:
fun main(args: Array<String>) {
var genList = mutableListOf<Char>()
genList.add('a')
genList.add('A')
genList.add('B')
genList.add('C')
println(genList)
}
Output:
[a, A, B, C]
val chars = "ABC".toList()
CharSequence has a to(Mutable)List extension function defined in kotlin.text.
fun CharSequence.toList(): List<Char>
Returns a List containing all characters.
kotlin-stdlib / kotlin.text / toList
fun CharSequence.toMutableList(): MutableList<Char>
Returns a MutableList filled with all characters of this char sequence.
kotlin-stdlib / kotlin.text / toMutableList
Kotlin's standard libraries have hundreds of utility functions like this, so chances are that most of the time what you want already exists.
Many standard types that conceptually model some sort of iterable data, but are not Iterable, have extensions defined on them that are equivalent to those in kotlin.collections.

is-check or a cast that involves the non-generic part of the type

I got a few question when I was reading the Kotlin reference:
In "Type erasure and generic type checks", it mention:
When you already have the type arguments of an instance checked statically (at compile
time), you can make an is-check or a cast that involves the non-generic part of the type. Note
that angle brackets are omitted in this case
and they gave a example:
fun handleStrings(list: List<String>) {
if (list is ArrayList) {
// `list` is smart-cast to `ArrayList<String>`
}
}
Q1: I test myself
val a = mutableListOf(1, 2, 3)
val b = listOf(1, 2, 3)
println(a is List) //error, should use List<*>
println(b is MutableList) //can compile
I don't understand why they got different result.
Q2: I found that I can't use smart cast from List to ArrayList
println(listOf(1, 2, 3) is ArrayList) //false
println(listOf(1, 2, 3) is MutableList) //true
As I remember, listOf() is implement by ArrayList in Kotlin, it calls asList, which return a ArrayList, in Arrays.java.
So, why can't listOf() smart cast to ArrayList?
A1: In the first case, you cast from subclass to superclass. It does not make any sense, since instance of subclass can always be used as an instance of superclass without casting:
val a: MutableList<Int> = mutableList(1, 2, 3)
val b: List<Int> = a
So the Kotlin compiler does not implement generic smart cast for casting upstairs and uses default rules of casting which require star projection.
In the second case you cast from superclass to subclass, so it works as intended.
A2: There are two different ArrayList classes. Try to run this code:
println(listOf(1, 2, 3)::class)
println(ArrayList<String>()::class)
It prints:
class java.util.Arrays$ArrayList
class java.util.ArrayList
listOf returns a nested class Arrays.ArrayList, not ArrayList you usually work with.

(imutable collection is mutable) returns true in Kotlin

Why this is happening in Kotlin:
val list: List<Int> = listOf(1, 2, 3)// Immutable list
if(list is MutableCollection<*>){// why this "if" condition is true?
println("is mutable")// this line is printed
(list as MutableCollection<Int>).add(4) // this results to java.lang.UnsupportedOperationException
}
list is MutableCollection returns true that shows Kotlin Immutable collection objects implements MutableCollection interface but instead of changing items in collection it throws UnsupportedOperationException
Is it true? and if yes why Immutable collection objects implement MutableCollection interface in Kotlin?
Is it because of Kotlin collections inherit from Java Collections and altering methods (add, remove, ...) already is there and the only way to avoid altering collection is to override it and throw an exception (even if this is true it is not necessary for Kotlin immutable collection objects to implement MutableCollection interface because java altering collection methods already are there and can be overridden)?
No, that's not the correct explanation. This code should help you understand what's going on:
val list: List<Int> = listOf(1, 2, 3)
println("list class is = ${list::class.java}")
if(list is MutableCollection<*>) {
println("is mutable")
(list as MutableList<Int>)[0] = 42
println(list)
}
The output is
list class is = class java.util.Arrays$ArrayList
is mutable
[42, 2, 3]
So, the explanation is that listOf(1, 2, 3) returns an Arrays$ArrayList list, i.e. the list that would be returned in Java by doing Arrays.asList(1, 2, 3). It is a mutable list, but you can't add anything to it, because it has a fixed size, since it's backed by an array.
Kotlin lists aren't truly immutable. They just don't have any method allowing to mutate them: they're just immutable interfaces that only expose the readonly methods of an actually mutable list. If you cheat and cast the list to a mutable list, then, if the list is in fact a Java List, the cast will succeed, but you can't know if you're actually be able to mutate them, just like in Java: a List could be an emptyList, which can't be mutated at all, or a non-resizable list as in the above example, or a fully mutable list like an ArrayList.

Get value from Dictionary<String, Any>

I declared a Dictionary<String, Any> which has some Strings, Arrays and ints as values.
When I try to get back a value based on String key, I'm not able to cast it to Array,
even if that value identified by key is a real Array.
let lColorValues = lTabBarDictionary[TabBarKey.tabBarColor] as Array;
p.s. TabBarKey.tabBarColor is a string
Apple's Swift Programming Book offers an example with an Array which store different kinds of objects, and they use as to downcast objects, which seems to work fine for Array but not for Dictionary.
Did I missed something ? How to get values for such Dictionary ?
You have to specify the type the Array holds, for example:
class TabBarKey {
class var tabBarColor : String {
return "key"
}
}
let arr = ["1", "2", "3"]
var lTabBarDictionary = Dictionary<String, Any>()
lTabBarDictionary[TabBarKey.tabBarColor] = arr
let val = lTabBarDictionary[TabBarKey.tabBarColor] as Array<String>
in the last line, I am using Array<String> instead of Array. You should do the same thing, using of course the proper generic type that the array holds.
Tested that code in playground and it prints the expected array.