I have a sortedBy{} statement which intends to sort a List by the length of the String elements:
var animals: List<String> = listOf("tiger", "cat", "dragon", "elephant")
fun strLength(it: String) = it.length
animals.sortedBy { strLength(it) }
animals.forEach {println(it)}
However it only prints the initial order. Any idea why?
You have to assign the output of sortedBy.
animals = animals.sortedBy { strLength(it) }
Because, like many other functions in Kotlin, sortedBy doesn’t mutate the input & honour immutability. So it returns a new collection. So it mitigates side-effects. Kotlin encourages this immutable approach. However, there are mutable counterparts of these collections if required.
sortedBy does not sort the list, instead it returns a new list which has the elements sorted. If you don't want a new list, simply use sortBy.
Related
I have managed to removeAll from a MutableList in-place successfully. This call modifies the receiver list to remove all elements matching the given predicate.
I would like to modify the receiver list by keeping only the first n elements but I cannot figure out how to do it since take and slice calls return a new collection.
Is there an in-place version of take or slice functions on MutableList?
An example of how I would like to use the new function: myList.keepFirst(5).
For keepFirst(n) and keepLast(n), you can get a subList(), then clear() it. This works because subList returns a "view" of the list, not a copy.
// suppose "l" is a MutableList
// keepFirst(5)
l.subList(5, l.size).clear()
// keepLast(5)
l.subList(0, l.size - 5).clear()
Another way this might be achieved:
private fun <T> MutableList<T>.keepFirst(n: Int) {
while (size > n) {
removeLast()
}
}
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>())
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!
I'm reading Kotlin docs. At Immutability sector, they comment below. I wonder why should we do that? When I tried the example code, it acts the same.
Immutability
Prefer using immutable data to mutable. Always declare local variables
and properties as val rather than var if they are not modified after
initialization.
Always use immutable collection interfaces ( Collection , List , Set ,
Map ) to declare collections which are not mutated. When using factory
functions to create collection instances, always use functions that
return immutable collection types when possible:
// Bad: use of mutable collection type for value which will not be mutated
fun validateValue(actualValue: String, allowedValues: HashSet<String>) { ... }
// Good: immutable collection type used instead
fun validateValue(actualValue: String, allowedValues: Set<String>) { ... }
// Bad: arrayListOf() returns ArrayList<T>, which is a mutable collection type
val allowedValues = arrayListOf("a", "b", "c")
// Good: listOf() returns List<T>
val allowedValues = listOf("a", "b", "c")
Updated: For anyone who voted me down. I read this book, tried the example and tried to search before writing this question. So I don't have enough experience to explain or comprehend the paragraph above. Let consider what you contribute to this community. If I do wrong, let me know. Don't click only one button.
As the suggestion of Mr.#Akavall and Mr.#Naetmul. I read the listOf method's docs again. The problem has I missed that the listOf method returns a list object that can't add any new item.
I think you should compare MutableList and List. Both are
interfaces, whereas ArrayList is a concrete class from Java.
ArrayList implements MutableList in Kotlin. MutableList
extends List, adding mutability functionalities which are not in
List originally.
I want to know actually how .indices works and what is the main difference is between this two for loops.
for (arg in args)
println(arg)
or
for (i in args.indices)
println(args[i])
And what is use of withIndex() function
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
These are just different ways to iterate over an array, depending on what you need access to within the body of the for loop: the current element (first case), the current index (second case), or both (third case).
If you're wondering about how they work under the hood, you can just jump into the code of the Kotlin runtime (Ctrl+B in IntelliJ), and find out.
For indices specifically, this is pretty simple, it's implemented as an extension property that returns an IntRange which a for loop can then iterate over:
/**
* Returns the range of valid indices for the array.
*/
public val <T> Array<out T>.indices: IntRange
get() = IntRange(0, lastIndex)
As mentioned in the documentation indices is the index value from the list.
Returns an IntRange of the valid indices for this collection.
For more details refer to the documentation
indices returns IntRange(range of index from first to the last position) of collection, for example:
val array= arrayOf(10,20,30,40,50,60,70)
println("Indices: "+array.indices) // output: Indices: 0..6
In the question, both the loop are doing the same thing and just different way of iterate any collection(as #zsmb13 mentioned) but, the 2nd for loop does not create an iterator object as the first one does.
indices returns IntRange so you must check these useful methods of IntRange
When I wrote
for (i in 0..searchResultsTemp.items.size-1 )
{ " la-la-la "},
I wanted to work with each item of the collection, but I wouldn't use forEach operator, I would have access to the index of the collection item.
Then the built-in Android Studio helper suggested to me to automatically replace this expression with
for (i in searchResultsTemp.items.indices)
{ " la-la-la "}
It is the same.