Initialize list with variable number of the same value - kotlin

Is there a way to initialize a list x times with the value of y?
Thus instead of:
mutableListOf(0, 0, 0, 0)
something like:
makeMutableList(4, 0)

Yes, just like this:
MutableList(4) { 0 }
This calls the factory function MutableList which takes a size and a lambda, passing to the lambda the index and setting the appropriate element to the result of the lambda. Thus, to create the list [1, 2, 3, 4] you can do this:
MutableList(4) { it + 1 }
If you don't need a mutable list, there is also a List factory function.
When running on the JVM, both List and MutableList functions create a java.util.ArrayList, though you shouldn't rely on the exact type.

Related

Kotlin MutableList.take in place?

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()
}
}

Why is dart wrongly inferring my generic parameter type?

I can't seem to understand why the mySet variable is being inferred as a generic set with dynamic parameter type, when I clearly equated it to an int set literal. So is this result logical or has dart genuinely failed to infer the generic sets parameter type?
main(){
Set mySet = {1 ,2 , 3};
var myProducts = {
1:'TV',2:'Refrigerator',
3:mySet.lookup(2),
4:'Tablet',
5:'Computer'
};
var userCollection = {"name":"John Smith","Email":"john#sanjib.site"};
myProducts.forEach((x,y) => print("${x} : ${y}"));
userCollection.forEach((k, v) => print("${k} : ${v}"));
}
If you declare a variable with a generic type Generic but omit the parameterized type, it's (usually1) shorthand for Generic<dynamic>. Inference does happen in your assignment, but not in the direction you expect: since you explicitly declared the type of mySet, the type of {1, 2, 3} is inferred from that explicit type (Set/Set<dynamic>) and becomes <dynamic>{1, 2, 3} instead of <int>{1, 2, 3}.
This is one reason why it can be better to omit explicit types and just allow types to be inferred when possible. Using:
var mySet = {1, 2, 3};
would allow mySet to be inferred as Set<int>. If you really want to use explicit types, you should ensure that you specify explicit types for generic type parameters too.
You can catch such errors by setting:
analyzer:
language:
strict-raw-types: true
in your analysis_options.yaml file. (You also might wish to enable:
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
too.)
Also see https://github.com/dart-lang/language/blob/master/resources/type-system/strict-raw-types.md:
void main() {
List a = [1, 2, 3];
}
Developers often think that inference fills in the type of a from the right side of the assignment. It may look like a has the type List<int>. But Dart fills in omitted type arguments, like E on List, with dynamic (or the corresponding type parameter's bound); List a; is purely a shorthand for List<dynamic> a;. Inference then flows from a onto the expression on the right side of the assignment.
1 Strictly speaking, if a generic's type parameter is constrained (e.g. class Generic<T extends Base>), then omitting the type parameter is shorthand for using that constraint (i.e., Generic would be shorthand for Generic<Base>). Most generics don't constraint their type parameters, so therefore it usually ends up being dynamic.

How to create list in 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)

RxKotlin flattenAsObservable(): type mismatch with method reference

I'm converting some Java code to Kotlin and I'm having some trouble with flattenAsObservable()
Here's what the code looked like in Java:
discogsInteractor.search(query)
.map(RootSearchResponse::getSearchResults)
.flattenAsObservable(searchResults -> searchResults)
.take(12)
Here's what I have so far in Kotlin:
discogsInteractor.search(query)
.map { RootSearchResponse::searchResults }
.flattenAsObservable<SearchResult> { searchResults -> searchResults }
.take(12)
It underlines the second searchResults and gives me the following error:
Required: (Mutable)Iterable<SearchResult!>!
Found: KProperty1<RootSearchResponse, List<SearchResult>>!
I can replace
.map { RootSearchResponse::searchResults }
with
.map { searchResponse -> searchResponse.searchResults }
and it will work. How do I correctly method reference? Or what's the reason that I can't in this instance?
RootSearchResponse:
data class RootSearchResponse(val pagination: Pagination,
#SerializedName("results") val searchResults: List<SearchResult>)
RootSearchResponse::searchResults is a method reference. Instead of passing this to the map function, by using {}, you're passing in a lambda that always returns this method reference.
Basically, you're mapping every incoming element to that method reference with your map operation, instead of applying that method to every element like you'd want to. So the incoming parameters of your flattenAsObservable method are always that same reference to the searchResults method, which is a KProperty1.
To apply the method that you're referencing to every element, you can pass the method reference in regular parentheses, like so:
.map(RootSearchResponse::searchResults)
For an additional simple example of what's happening with the lambda:
listOf(1, 2, 3, 4, 5).map { 2 }
This operation would map every element to 2, and you'd end up with a list that only contains 2 five times. It's basically just shorthand for the following, just without an explicit parameter name:
listOf(1, 2, 3, 4, 5).map { x -> 2 }

What is .indices meaning in kotlin?

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.