I was going through some Kotlin basics and found two syntaxes.
ArrayList<String>()
And
arrayListOf<String>()
What is the difference between these two as both are part of Kotlin.Collections?
arrayListOf<T>() is mainly there for your convenience. vararg-functions usually come with a (sometimes negligible) performance impact and switching between the arrayListOf(someElements...) and arrayListOf() without that convenience method would basically delegate that problem to you as a programmer. You have to know it and you would have to change that code to ArrayList(), if such an impact is affecting you and if that convenience function wouldn't exist.
arrayListOf() is basically just that. It returns ArrayList() and it is inlined. That's just convenient, so that you don't really have to think about it, when you switch back and forth between arrayListOf(someElements) and arrayListOf().
That having said: there is no difference between arrayListOf() and ArrayList() as also others have already mentioned and arrayListOf(elements) is the convenience variant to construct an ArrayList with the given elements.
arrayListOf is a function, that has optional variable length arguments
In case of using it without arguments, there is no difference
arrayListOf<T>()
is just an extension function that looks like this:
public inline fun <T> arrayListOf(): ArrayList<T> = ArrayList()
it a function is right but is use of like this
here in function used set() function of arrayListOf() is used to set the given element at specified index and replace if any element already present at that index
fun main(args: Array<String>){
val list: ArrayList<String> = arrayListOf<String>()
list.add("Ajay")
list.add("Vijay")
list.add("Prakash")
println(".......print list.......")
for (i in list) {
println(i)
}
println(".......arrayList.set(2,\"Rohan\").......")
list.set(2,"Rohan")
println(".......print ArrayList.......")
for (i in list) {
println(i)
}
}
Output
.......print list.......
Ajay
Vijay
Prakash
.......list.set(2,"Rohan").......
.......print list.......
Ajay
Vijay
Rohan
When creating an empty array, you can use either:
val emptyArray1 = ArrayList()
val emptyArray2 = arrayListOf()
But when creating an array from existing elements, you have to use one or the other depending on whether the existing elements are already in a collection or you want to specify them individually:
val arrayFromCollection = ArrayList(hashMap.keys)
val arrayFromElements = arrayListOf("1", "2", "3")
Note that you can use the spread operator to pass an existing collection into arrayListOf as individual elements, but if the collection is anything other than another array, you also need to convert it to an array. This probably isn't worth the extra verbosity:
val arrayFromCollectionVerbose = arrayListOf(*hashMap.keys.toTypedArray())
Related
I wrote an extension function to get an element of an JSON object by its name:
fun JSONObject.obj (name: String): JSONObject? =
try { this.getJSONObject(name) }
catch (e: JSONException) { null }
Now I want to extend this for nested JSON objects. I wrote the following:
tailrec fun JSONObject.obj (first: String, vararg rest: String): JSONObject? =
if (rest.size == 0)
obj(first)
else
obj(first)?.obj(rest[0], *rest.drop(1).toTypedArray())
But this looks quite inefficient to me.
What is the best way to slice a vararg argument?
We could use vararg only in the public function, but then internally use list for recursion:
fun JSONObject.obj (first: String, vararg rest: String): JSONObject? = obj(first, rest.asList())
private tailrec fun JSONObject.obj (first: String, rest: List<String>): JSONObject? =
if (rest.size == 0)
obj(first)
else
obj(first)?.obj(rest[0], rest.subList(1, rest.size))
Both asList() and subList() don't copy data, but only wrap the existing collection. Still, this is far from ideal, because it creates a new object for each iteration and it may create a chain of views (it depends on internal implementation of subList()). Alternatively, the internal function could receive an array and offset - this will solve both above problems.
Generally, I suggest to not try turning Kotlin into something it is not. It has limited support for functional constructs, but it is not a functional language. Without the linked list implementation which could be easily split into head and tail, this style of code will be always inefficient and/or cumbersome. You can look for such implementation, for example in Arrow or kotlinx.collections.immutable. The latter has ImmutableList with optimized subList() - you can use it with the solution provided above to avoid creating a chain of lists.
Update
As a matter of fact, basic lists implementations in the Java stdlib also provide optimized subList(): AbstractList.java. Therefore, the above solution using simply asList() should be fine, at least when targeting JVM.
Instead of slicing, why don't you try just iterating over all the objects and getting the JSONObjects? I think this would be much more efficient.
fun JSONObject.obj(vararg names: String): JSONObject? {
var jsonObject = this
for (name in names) {
if (!jsonObject.has(name))
return null
jsonObject = jsonObject.getJSONObject(name)
}
return jsonObject
}
I have the following code but I am convinced that it could be simpler/more elegant
package org.example
import javax.enterprise.context.ApplicationScoped
#ApplicationScoped
object CanceledRequestsHandler {
var identifiers = setOf<String>()
fun add(id: String){
var mutableIdentifiers = identifiers.toMutableList()
mutableIdentifiers.add(id)
this.ids = mutableIds.toSet()
}
}
I wanted to limit the mutability. Any suggestions t improve my code?
There is a more elegant way! Try this script file (.kts) with kotlinc (or you can run it within IDEA):
object CanceledRequestsHandler {
var ids = setOf<String>()
override fun toString(): String = ids.toString()
fun add(id: String){
ids = ids + id
}
}
System.err.println(CanceledRequestsHandler);
CanceledRequestsHandler.add("foo");
CanceledRequestsHandler.add("bar");
System.err.println(CanceledRequestsHandler);
A bit of explanation:
The + operator can be applied to collections, and works as one might expect -- returns a new collection (see https://kotlinlang.org/docs/reference/collection-plus-minus.html).
I'm not sure what your separate identifiers variable was, but you can use a single var that contains an immutable Set to do your job here.
As a commenter and the accepted answer point out, there's more you can do. If you're trying to limit mutability entirely to add(), you can lock this down further, with something like this:
object CanceledRequestsHandler {
private var _ids = mutableSetOf<String>()
val ids
get() = _ids.toSet()
override fun toString(): String = ids.toString()
fun add(id: String) {
_ids.add(id)
}
}
System.err.println(CanceledRequestsHandler);
CanceledRequestsHandler.add("foo");
CanceledRequestsHandler.add("bar");
System.err.println(CanceledRequestsHandler);
// Below line does not compile
// CanceledRequestsHandler.ids.add("baz")
Now the only way the ids property can change is via the add() method.
I wanted to limit the mutability
Converting immutable collection to mutable on each data mutation is not a limitation of mutablility, it's just overhead. The worst here is that property is declared as mutable (var). This design may lead to data loss in multi-thread case.
If data mutation is unavoidable, then it's better to have mutable (concurrent in multi-thread case) data collection with immutable property (val).
Even better way to limit mutability will be using a mutable data structure only for a short initialization period, and then freezing it into immutable (see buildSet), but I'm not sure that this approach is applicable in your case.
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>())
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.
In Kotlin I created an extension function to initialise a new ArrayList with custom items, like this:
fun <T> arrayListFrom(vararg item: T): ArrayList<T> {
return item.toMutableList() as ArrayList<T>
}
In this way I can easily create an arraylist like this
arrayListFrom(MyCustomItem(1), MyCustomItem(2))
... without creating a new-empty one, and adding all elements to it one by one
Kotlin has so many useful functions for collections, I cannot imagine I need this extension for easy arrayList initialisation, but couldn't find another simple way. Am I missing out on some useful Kotlin function here?
arrayListOf(items)
So you can just do
arrayListOf(MyCustomItem(1), MyCustomItem(2))
One more easy way to initialize ArrayList not exactly one line.
object: ArrayList<instanceType>() {
init{
add(instance1)
add(instance2)
}
}
Another nifty trick is to leverage Kotlin's basic Array type. Its constructor has an optional init function which allows for cool and simple inits like so val newArray = Array(2) { MyCustomItem(i+1) } which would make [ MyCustomItem(1), MyCustomItem(2) ].
To get an arrayList out of it, just add toCollection(ArrayList()) to the end like so
val newArrayList = Array(2) { MyCustomItem(i+1) }.toCollection(ArrayList())
and presto! The array gets created, and the items get sent to a destination arrayList. You can use the arrayList as needed, and it was done in only one line!
Disclaimer: It's probably slower given the transfer involved under the hood, so use with care of course!