I've been trying sequence programming for processing the data I get from the vararg argument. I want to multiply every number in the list and add it to the new array list. Is it possible to use sequences.
I attach the code below:
fun main() {
val number = asList(10, 20, 30, 40, 50)
print(number)
}
fun <T> asList(vararg input: T): List<T> {
val result = ArrayList<T>()
input.map {it * 2}.foreach(result.add(it))
return result
}
Here is the error I get:
enter image description here
Yes, it's possible to create a sequence from a vararg; I'll come back to that later.
First, the main problem in the code above is that, unfortunately, it can't be done generically. The error you're getting is because T could be any type, and most types can't be multiplied, so the compiler is telling you that you can't do the * 2.
You might think of restricting T to subclasses of Number, but that doesn't help. (Number is a very weak type; it doesn't let you do any arithmetic, probably because you can't tell what type the result would have to be, nor what rounding or overflow might occur. All it lets you do is convert the value to specific types.)
But if you remove the type parameter and code it for a particular numeric type, such as Int, then it can work fine.
There are also spelling and syntax errors in the code around the foreach call. Fixing those too gives e.g.:
fun asList(vararg input: Int): List<Int> {
val result = ArrayList<Int>()
input.map{ it * 2 }.forEach{ result.add(it) }
return result
}
That's doing a lot of unnecessary work, though; the map() already returns a list, so there's no point in creating a second list and copying to it element-by-element! Also, the name is misleading. So it could just be:
fun asListDoubled(vararg input: Int) = input.map{ it * 2 }
Your question mentioned sequences; but your code uses normal eager lists. If you want a lazily-evaluated sequence, you can just add an asSequence() call, e.g.:
fun asSequenceDoubled(vararg input: Int) = input.asSequence().map{ it * 2 }
But note that this now returns a Sequence<Int>, not List<Int>, so you can go on and do further lazy operations on it. (If you want a List<Int>, then you can just append a toList() call — but there's little point in using a sequence only for the doubling, as the sequence overhead is probably far higher than any saving.)
Related
I'm creating a list of values, in a context where it so happens that, though the values are being added one at a time, the eventual number is known in advance. This is in a function that will be called many times, so the faster it runs, the better.
In Java, I would use the ArrayList constructor that specifies an initial capacity, because in theory this makes it slightly faster because it avoids resizing.
In Kotlin, one normally uses mutableListOf(), but this does not allow an initial capacity; in theory this should result in slightly slower code.
Is the recommended/idiomatic Kotlin solution in this case:
Go ahead and use the ArrayList constructor; ArrayList is a perfectly valid MutableList.
Ignore the issue; the initial capacity never actually makes a measurable difference to speed.
Something else?
Fill an immutable list
val doubles = List(5) { i -> i * 2 }
result --> [0, 2, 4, 6, 8]
Fill a mutable list of five elements with zeros
val ints = MutableList(5) { 0 }
result --> [0, 0, 0, 0, 0]
Updated Answer
I was actually confused with capacity and size. There is no implementation of using a default capacity MutableList currently in Kotlin stdlib.
You can make one yourself.
fun <T> mutableListWithCapacity(capacity: Int): MutableList<T> =
ArrayList(capacity)
// creates a MutableList of Int with capacity of 5.
val mutableList = mutableListWithCapacity<Int>(5)
Outdated Answer
One of the reason why mutableListOf does not allow for default capacity is because default values in kotlin is not null.
However there is a utility function defined in kotlin.collections package.
public inline fun <T> MutableList(size: Int, init: (index: Int) -> T): MutableList<T> {
val list = ArrayList<T>(size)
repeat(size) { index -> list.add(init(index)) }
return list
}
You can create a List with a List function or MutableList function with a default capacity and its mapping.
// creates a list of ints with default capacity of 10 and having nulls.
// But I highly doubt you should initialize it with a null since Kotlin is a null-safe language.
val list = MutableList<Int?>(10) { null }
But since there should not be nulls in Kotlin if it is intended use of non-null list else you have to do a null check using operators like ?. !!..
You can wrap this mutableList() predefined function in a function like the following
fun <E> emptyMutableList(size: Int = 0): MutableList<E?> {
return MutableList(size) {
null
}
}
this will return a MutableList of size size but also with null assigned to all of its cells. Now if you want to access any index value, your program will not crash with java.lang.IndexOutOfBoundsException like it would if you use the solution in the accepted answer. Here is what I mean:
fun <E> emptyMutableList(size: Int = 0): MutableList<E?> {
return MutableList(size) {
null
}
}
fun <T> mutableListWithCapacity(capacity: Int): MutableList<T> =
ArrayList(capacity)
fun main() {
val mutableList1 = mutableListWithCapacity<Int>(20)
val mutableList2 = emptyMutableList<Int>(20)
mutableList1[10] // this will throw a java.lang.IndexOutOfBoundsException
mutableList2[10] // this will not throw an exception but it will return null
}
Of course everything depends on how memory efficient vs crash-free you want your program to be.
Happy coding!
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.
Let's say for examples sake that I wanted to write my own sum function, which can take either a collection of ints or vararg ints, like in the following:
fun sum(ints: Collection<Int>): Int {
var result = 0
for (i in ints)
result += i
return result
}
fun sum(vararg ints: Int) = sum(ints.toSet())
Is there a better/idiomatic way to define a function for both parameter types? In many cases I only use such functions for one or two element, so wrapping it with listOf() outside of the function every time seems clunky to me.
I think there is no a better way of doing that. You can either use your example or this one:
fun sum(ints: Collection<Int>) = sum(*ints.toIntArray())
fun sum(vararg ints: Int): Int {
var result = 0
for (i in ints)
result += i
return result
}
Is there a better/idiomatic way to define a function for both
parameter types?
Since both are different types so it's not possible with a function only. You approach is okay.
But you pass an Array as vararg argument using spread operator (*)
I'm creating a list of values, in a context where it so happens that, though the values are being added one at a time, the eventual number is known in advance. This is in a function that will be called many times, so the faster it runs, the better.
In Java, I would use the ArrayList constructor that specifies an initial capacity, because in theory this makes it slightly faster because it avoids resizing.
In Kotlin, one normally uses mutableListOf(), but this does not allow an initial capacity; in theory this should result in slightly slower code.
Is the recommended/idiomatic Kotlin solution in this case:
Go ahead and use the ArrayList constructor; ArrayList is a perfectly valid MutableList.
Ignore the issue; the initial capacity never actually makes a measurable difference to speed.
Something else?
Fill an immutable list
val doubles = List(5) { i -> i * 2 }
result --> [0, 2, 4, 6, 8]
Fill a mutable list of five elements with zeros
val ints = MutableList(5) { 0 }
result --> [0, 0, 0, 0, 0]
Updated Answer
I was actually confused with capacity and size. There is no implementation of using a default capacity MutableList currently in Kotlin stdlib.
You can make one yourself.
fun <T> mutableListWithCapacity(capacity: Int): MutableList<T> =
ArrayList(capacity)
// creates a MutableList of Int with capacity of 5.
val mutableList = mutableListWithCapacity<Int>(5)
Outdated Answer
One of the reason why mutableListOf does not allow for default capacity is because default values in kotlin is not null.
However there is a utility function defined in kotlin.collections package.
public inline fun <T> MutableList(size: Int, init: (index: Int) -> T): MutableList<T> {
val list = ArrayList<T>(size)
repeat(size) { index -> list.add(init(index)) }
return list
}
You can create a List with a List function or MutableList function with a default capacity and its mapping.
// creates a list of ints with default capacity of 10 and having nulls.
// But I highly doubt you should initialize it with a null since Kotlin is a null-safe language.
val list = MutableList<Int?>(10) { null }
But since there should not be nulls in Kotlin if it is intended use of non-null list else you have to do a null check using operators like ?. !!..
You can wrap this mutableList() predefined function in a function like the following
fun <E> emptyMutableList(size: Int = 0): MutableList<E?> {
return MutableList(size) {
null
}
}
this will return a MutableList of size size but also with null assigned to all of its cells. Now if you want to access any index value, your program will not crash with java.lang.IndexOutOfBoundsException like it would if you use the solution in the accepted answer. Here is what I mean:
fun <E> emptyMutableList(size: Int = 0): MutableList<E?> {
return MutableList(size) {
null
}
}
fun <T> mutableListWithCapacity(capacity: Int): MutableList<T> =
ArrayList(capacity)
fun main() {
val mutableList1 = mutableListWithCapacity<Int>(20)
val mutableList2 = emptyMutableList<Int>(20)
mutableList1[10] // this will throw a java.lang.IndexOutOfBoundsException
mutableList2[10] // this will not throw an exception but it will return null
}
Of course everything depends on how memory efficient vs crash-free you want your program to be.
Happy coding!
mapIndexed on an array curiously returns a List not an array which isn't immediately intuitive.
I also noticed that kotlin.collections.mapIndexed documentation does not mention retention of ordering but kotlin.sequences.mapindexed does.
I know that since it's not explicit in the doc, I shouldn't rely on it, but wondering if it's an intentional omission.
I believe it is an omittion, it wouldn't be that practical to change the order of the elements, it would be highly unperformant.
The order is at least guaranteed by the implementation of the method as you can see below.
An enhanced for loop is used to loop through the whole collection and it applies the change only to the concerned index.
The fact that it returns a List is logical, since you'll get the same List back (actually a full copy - but with the same objects), only with the changes required.
/**
* Applies the given [transform] function to each element and its index in the original collection
* and appends the results to the given [destination].
* #param [transform] function that takes the index of an element and the element itself
* and returns the result of the transform applied to the element.
*/
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapIndexedTo(destination: C, transform: (index: Int, T) -> R): C {
var index = 0
for (item in this)
destination.add(transform(checkIndexOverflow(index++), item))
return destination
}
Order is retained in the results.
Check out my code here - changing the first item in the list:
val convertedResults = mutableListOf<DisplayItem>()
myList.mapIndexedNotNullTo(convertedResults) { index, item ->
val member = DisplayItem(item)
if (member.id == "id_007") {
// add it first in the list
convertedResults.add(0, member)
null
} else
member
}
This works well. But I don't know how to measure the performance here. Tell me what do you think about this code.
An indication that the order is retained is also in /libraries/stdlib/test/collections/IterableTests.kt (link to latest revision in master at this time) of the official Kotlin repository
abstract class IterableTests<T : Iterable<String>>(val createFrom: (Array<out String>) -> T, val empty: T) {
fun createFrom(vararg items: String): T = createFrom(items)
val data = createFrom("foo", "bar")
[...]
#Test
fun mapIndexed() {
val shortened = data.mapIndexed { index, value -> value.substring(0..index) }
assertEquals(2, shortened.size)
assertEquals(listOf("f", "ba"), shortened)
}
So the test also assumes the same order for output. This is odd by the way as this code is not only used for testing List and others but also for testing an unordered Set.
Similar code is used for testing mapIndexed on arrays of all types.