How do I sum all the items of a list of integers in Kotlin? - kotlin

I have a list of integers, like:
val myList = listOf(3,4,2)
Is there any quick way in Kotlin to sum all the values of the list? or do I have to use a loop?
Thanks.

You can use the .sum() function to sum all the elements in an array or collection of Byte, Short, Int, Long, Float or Double. (docs)
For example:
val myIntList = listOf(3, 4, 2)
myIntList.sum() // = 9
val myDoubleList = listOf(3.2, 4.1, 2.0)
myDoubleList.sum() // = 9.3
If the number you want to sum is inside an object, you can use sumOf to select the specific field you want to sum: (docs)
data class Product(val name: String, val price: Int)
val products = listOf(Product("1", 26), Product("2", 44))
val totalCost = products.sumOf { it.price } // = 70
Note: sumBy was deprecated in Kotlin 1.5 in favour of sumOf.

The above answer is correct, as an added answer, if you want to sum some property or perform some action you can use sumBy like this:
sum property:
data class test(val id: Int)
val myTestList = listOf(test(1), test(2),test(3))
val ids = myTestList.sumBy{ it.id } //ids will be 6
sum with an action
val myList = listOf(1,2,3,4,5,6,7,8,9,10)
val addedOne = myList.sumBy { it + 1 } //addedOne will be 65

The above answers are correct but, this can be another way if you also want to sum all integers, double, float inside a list of Objects
list.map { it.duration }.sum()

sumBy is Deprecated new use sumOf instead
val data = listOf(listOf(1, 2, 3), listOf(4, 5, 6))
println(data.sumOf { it.size }) // 6
println(data.sumOf { innerList -> innerList.sumOf { it } }) //21
println(data.sumOf { innerList -> innerList.sum() }) // 21

Related

How to initiate array items using for loop in Kotlin

Python allows programmers to perform such an operation:
mylist = [1, 2]
items = [value * 2 for value in namelist]
How can I achieve the same using Kotlin, I want to pass values multiplied by 2 from mylist into the array below:
val mylist = mutableListOf(1, 2)
val (first, second) = arrayOf( )
Kotlin allows us to to declare and initiate variables with one liners as below
val (first, second) = arrayOf(1, 2) that way you can call first or second as a variable. Am trying to make the equal part dynamic
Equivalent of the above Python code in Kotlin is:
val mylist = listOf(1, 2)
val items = mylist.map { it * 2 }
If you need to assign resulting doubled values to first and second, then do it exactly as you did:
val (first, second) = mylist.map { it * 2 }
You need to be sure myList contains at least 2 items.
Try this out:
// === KOTLIN
var mylist = listOf(1, 2)
val result = mylist.map { it * 2 }
println(result)
// output: [ 2,4 ]

Kotlin: mutable map of mutable list won't update the list

(Kotlin newbie here) I have a text file with rows that look like these:
1-1-1
1-1-2
1-1-3
2-1-1
2-1-2
etc.
I have to transform these data to a map where the key is the first 2 elements and the value is a list of the third elements that that match the key. For example, the above records will transform into this JSON:
1-1: [1, 2, 3]
2-1: [1, 2]
etc.
I'm unable to increment the list. Here's a simplified version, I get stuck on the "else":
fun main () {
val l1 = mutableListOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
val m = mutableMapOf<String, List<Int>>()
for (e in l1) {
val c = e.split("-")
val key = "${c[0]}-${c[1]}"
if (m[key] == null) m[key] = listOf(c[2].toInt())
else println("How do I append to the list?")
}
println(m)
}
Output:
{1-1=[1], 2-1=[1]}
But I want:
{1-1=[1, 2, 3], 2-1=[1, 2]}
Thank you (comments about idiomatic form are welcome!)
If we continue to follow your strategy, what you need is for the value type to be a MutableList. Then you can add to the existing MutableList when there's already an existing list for that key:
fun main() {
val l1 = mutableListOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
val m = mutableMapOf<String, MutableList<Int>>()
for (e in l1) {
val c = e.split("-")
val key = "${c[0]}-${c[1]}"
if (m[key] == null) m[key] = mutableListOf(c[2].toInt())
else m[key]!!.add(c[2].toInt())
}
println(m)
}
This can be more natural using getOrPut(). It returns the existing MutableList or creates one and puts it in the map if it's missing. Then we don't have to deal with if/else, and can simply add the new item to the list.
fun main() {
val l1 = mutableListOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
val m = mutableMapOf<String, MutableList<Int>>()
for (e in l1) {
val c = e.split("-")
val key = "${c[0]}-${c[1]}"
m.getOrPut(key, ::mutableListOf).add(c[2].toInt())
}
println(m)
}
But we can use the map and groupBy functions to create it more simply:
val m = l1.map { it.split("-") }
.groupBy(
{ "${it[0]}-${it[1]}" }, // keys
{ it[2].toInt() } // values
)
You can achieve your desired output with a single call to groupBy of the Kotlin standard library.
val input = listOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
val result = input.groupBy(
{ it.substringBeforeLast("-") }, // extract key from item
{ it.substringAfterLast("-").toInt() } // extract value from item
)
The first lambda function extracts the key to group by of every list item. The second lambda function provides the value to use for each list item.
You can also do it by first mapping your values to Pairs and then group them as follows:
fun main(args: Array<String>) {
val input = listOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
val result = input.map {
val values = it.split("-")
"${values[0]}-${values[1]}" to values[2]
}.groupBy ({ it.first }) { it.second }
println(result)
}

How to use destructuring declarations to get multiple value from single map iteration?

data class Person(val name: String, val age: String, val color: String)
val persons = listOf(Person("john", "20", "green"), Person("Mary", "20", "blue"))
val names = persons.map {it.name}
val ages = persons.map {it.age}
val colors = persons.map {it.color}
// I will need 3 iteration to get my names and ages and colors
val personsMap = persons.map { it.name to it.age }
val (names2, ages) = personsMap.unzip()
// I am using 1 iteration but with Map and uzip(), I can get names2,
// ages within a single iteration
// Now if I wish to get color
// By using map, or alternatives call helper.. can I retrieve names,
// ages and colors at one go
// I do know that we can use iteration forEachloop and add into a
// set/list, but
// are there better way of doing it
// val (names, ages, colors)
What are the alternative way to write to get multiple value in a single iteration to get its list from destructing.
In order to collect lists of different properties, at least one iteration is required. this can be done by defining an extension function as
fun List<Person>.collectProperties(): Triple<List<String>, List<String>, List<String>>{
val (names, ages, colors) = listOf(mutableListOf<String>(), mutableListOf(), mutableListOf())
this.forEach { person ->
names.add(person.name)
ages.add(person.age)
colors.add(person.color)
}
return Triple(names, ages, colors)
}
now you can use this as
val persons = listOf(Person("john", "20", "green"), Person("Mary", "20", "blue"))
val(names, ages, colors) = persons.collectProperties()
Your toList() call is redundant, so you're iterating 3 times instead of twice.
I can't think of a way to do this with a single iteration using standard library higher-order functions. You could write a function like this that maps and unzips in one step so it only iterates once:
inline fun <T, U, V> Iterable<T>.doubleMap(transform: (T) -> Pair<U, V>): Pair<List<U>, List<V>> {
val size = if (this is Collection<*>) size else 10
val listU = ArrayList<U>(size)
val listV = ArrayList<V>(size)
for (t in this) {
with (transform(t)) {
listU += first
listV += second
}
}
return listU to listV
}

How to converter list of tuples to tuple of lists?

I have the example to show what I mean:
fun makeRange(i: Int) = Pair(i - 1, i + 1)
val listOfData = listOf(1, 2, 3, 4, 5, 6)
val pairs = listOfData
.map { makeRange(it) }
val leftRange = pairs.map { it.first }
val rightRange = pairs.map { it.second }
I have some list and function which returns a tuple. But the result I need is touple of two lists. I need something like that:
// can I get something like that ?
val (leftRange, rightRange) = listOfData.map { makeRange(it) } ...
Is there a way to do it?
If you really want to destructure it like this, I would also split up your makeRange-function, e.g.:
fun makeLeftRange(i: Int) = i - 1
fun makeRightRange(i: Int) = i + 1
fun makeRange(i: Int) = makeLeftRange(i) to makeRightRange(i) // if you still need it...
Then you can destructure as follows:
val (leftRange, rightRange) = listOfData.map(::makeLeftRange) to listOfData.map(::makeRightRange)
Or if it is really just such an easy function, why not just use the following instead:
val (leftRange, rightRange) = listOfData.map(Int::dec) to listOfData.map(Int::inc)
// or
val (leftRange, rightRange) = listOfData.map { it - 1 } to listOfData.map { it + 1 }
If you want to keep your makeRange as is and want to do it that way, it will get a bit uglier, e.g.:
val (leftRange, rightRange) = listOfData.map(::makeRange).let {
listOfPairs -> listOfPairs.map { it.first } to listOfPairs.map { it.second }
}
Basically reusing what you've shown in an additional let-statement.
Seems like kotlin unzip function is just what you're looking for.
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/unzip.html
In your example the usage would look something like
val (leftRange, rightRange) = pairs.unzip()

Sum a subset of of numbers in a list

Is there a way in Kotlin for doing the sum() operation on a filtered list of numbers, without actually filtering out the elements first?
I'm looking for something like this:
val nums = listOf<Long>(-2, -1, 1, 2, 3, 4)
val sum = nums.sum(it > 0)
You can make use of Iterable<T>.sumBy:
/**
* Returns the sum of all values produced by [selector] function applied to each element in the collection.
*/
public inline fun <T> Iterable<T>.sumBy(selector: (T) -> Int): Int {
var sum: Int = 0
for (element in this) {
sum += selector(element)
}
return sum
}
You can pass a function to it where the function transforms negative value to 0. So, it sums up all values in the list which is greater than 0 since adding 0 makes no effect to the result.
val nums = listOf<Long>(-2, -1, 1, 2, 3, 4)
val sum = nums.sumBy { if (it > 0) it.toInt() else 0 }
println(sum) //10
If you require a Long value back, you have to write an extension for Long just like Iterable<T>.sumByDouble.
inline fun <T> Iterable<T>.sumByLong(selector: (T) -> Long): Long {
var sum: Long = 0
for (element in this) {
sum += selector(element)
}
return sum
}
Then, the toInt() conversion can be taken away.
nums.sumByLong { if (it > 0) it else 0 }
As suggested by #Ruckus T-Boom, if (it > 0) it else 0 can be simplified using Long.coerceAtLeast() which returns the value itself or the given minimum value:
nums.sumByLong { it.coerceAtLeast(0) }
sumBy and sumByDouble are Deprecated from kotlin 1.5 . You can check those link.
Use sumOf to get sum on a List or Array
sumOf
Returns the sum of all values produced by selector function applied to each element in the collection or Array.
Example:
data class Order(
val id : String,
val price : Double
)
val orderList = ......
val sum = orderList.sumOf { it.price }
data class Product(val name: String, val quantity: Int) {
}
fun main(args: Array<String>) {
val productList = listOf(
Product("A", 100),
Product("B", 200),
Product("C", 300)
)
val totalPriceInList1: Int = productList.map { it.quantity }.sum()
println("sum(): " + totalPriceInList1)
val totalPriceInList2: Int = productList.sumBy { it.quantity }
println("sumBy(): " + totalPriceInList2)
}
this is the result of our code
sum(): 600
sumBy(): 600