How do we know which element is minimum in loop kotlin - kotlin

Hey I have list in kotlin. I am iterating over it. I want to store true/false as flag index which one is minimum value in whole list. I tried some code, but it's not working.
fun main() {
val list = mutableListOf(4.83, 4.39, 3.58, 3.50, 3.46)
val minValue = mutableListOf<BestMinimumValue>()
var previousValue = 0.0
list.forEach {
minValue.add(BestMinimumValue(compareValue = previousValue > it))
previousValue = it
}
minValue.forEach {
println(it)
}
}
data class BestMinimumValue(
val compareValue: Boolean
)
Actual Output
BestMinimumValue(compareValue=false)
BestMinimumValue(compareValue=true)
BestMinimumValue(compareValue=true)
BestMinimumValue(compareValue=true)
BestMinimumValue(compareValue=true)
I'll explain what I need. In my list 3.46 is minimum value so on that place I need the flag as true and other one will be false.
Expected Output
BestMinimumValue(compareValue=false)
BestMinimumValue(compareValue=false)
BestMinimumValue(compareValue=false)
BestMinimumValue(compareValue=false)
BestMinimumValue(compareValue=true)

It is not possible to create the resulting list while iterating, because we can't know if the current item is the smallest one or not. We have to iterate at least twice: first searching for the minimum value and then creating a resulting list.
One solution is to find the minimum and then compare items to it:
val min = list.minOrNull()!!
val minValue = list.map { BestMinimumValue(it == min) }
Note if there are multiple same minimum values, then all of them will be marked as true.
If this is not expected behavior or if we like to avoid comparing items twice, then we can find the index of the minimum value and just construct the resulting list with it:
val minIndex = list.withIndex().minByOrNull { it.value }!!.index
val minValue = List(list.size) { BestMinimumValue(it == minIndex) }

Related

Write a kotlin program that prints the number that is repeated the most in a consecutive way

I'm kind of stuck, I don't know how to make the second loop to start 1 position above the first loop in Kotlin.
I have an array (named myArray) with 10 elements, I need to Write a Kotlin program that prints the number that has the most consecutive repeated number in the array and also prints the number of times it appears in the sequence.
The program must parse the array from left to right so that if two numbers meet the condition, the one that appears first from left to right will be printed.
Longest: 3
Number: 8
fun main() {
val myArray: IntArray = intArrayOf(1,2,2,4,5,6,7,8,8,8)
for((index , value) in myArray.withIndex()){
var inx = index + 1
var count = 0
var longest = 0
var number = 0
for((inx,element) in myArray.withIndex()) {
if(value == element ){
count+=
}
}
if(longest < count){
longest = count
number = value
}
}
}
I'm against just dropping answers, but it is quite late for me, so I'll leave this answer here and edit it tomorrow with more info on how each part works. I hope that maybe in the meanwhile it will help you to gain some idea to where you might be going wrong.
val results = mutableMapOf<Int, Int>()
(0..myArray.size - 2).forEach { index ->
val current = myArray[index]
if (current == myArray[index + 1]) {
results[current] = (results[current] ?: 1) + 1
}
}
val (max, occurrences) = results.maxByOrNull { it.value } ?: run { println("No multiple occurrences"); return }
println("Most common consecutive number $max, with $occurrences occurrences")
Alternatively if the intArray would be a list, or if we allowed to change it to a list myArray.toList(), you could replace the whole forEach loop with a zipWithNext. But I'm pretty sure that this is a HW question, so I doubt this is the expected way of solving it.
myList.zipWithNext { a, b ->
if (a == b) results[a] = (results[a] ?: 1) + 1
}

Count sum of all list elements until condition is satisfied

I faced the following problem: I have a list of objects. Let it be objects of the class Test:
data class Test(
var status: String, // Can be EXPIRED, WAIT
var amount: Float
)
The array is sorted, there are objects with the status EXPIRED in the beginning and after objects with the status WAIT located. I need to calculate the sum of all elements with the status EXPIRED (if they exist) and add to this sum amount of the first object with the type WAIT (if it exists). Now I have the following code:
private fun getRestructuringAmountToPay(): Float {
var i = 0
var sum = 0F
list?.forEachIndexed { iter, el ->
if (el.status != RestructingItemStatus.WAIT) {
i = iter
sum += el.amount ?: 0F
}
}
if (i + 1 < (list?.size ?: 0)) {
sum += list?.get(i+1)?.amount ?: 0F
}
return sum
}
But is there any way to improve this code and make it Kotlin-pretty? Thanks in advance for any help!
since your list is sorted and EXPIRED items are first you can use firstOrNull
to find the first item with status == WAIT
while you iterate over EXPIRED items you can use a simple variable to sum the amount and when you found the first WAIT item just assign the sum to amount
var sum: Float = 0f
list.firstOrNull {
sum += it.amount
it.status == "WAIT"
}?.apply {
this.amount = sum
}
I would go old school and use a for loop rather than the forEachIndexed method so that I can break out of the loop when I hit the first WAIT entry. I'd do something like this:
private fun getRestructuringAmountToPay(): Float {
var sum = 0F
for (el in list) {
if (el.status == RestructingItemStatus.WAIT) {
el.amount += sum
break
}
else {
sum += el.amount
}
}
return sum
}
This is a simple and elegant way to do the bare minimum amount of work without any extra iterations over the list. If you're one of the "I have to cram everything into as few lines of code as possible" crowd, there are certainly more sophisticated and compact ways to go about this. I often struggle to understand the actual advantage of such solutions.
When you say you want to find all of the elements in the list with the status "EXPIRED", that makes me think of filter(). When you say you want to sum them, that makes me think of sumBy(). And when you say you want to add that number to the first element in the list with the status "WAIT", that makes me think of first().
We can't actually use the normal sumBy() function because Test.amount is of type Float, so the closest we can do is use sumByDouble() and convert amount to a Double.
val expiredSum = list.filter { it.status == "EXPIRED" }.sumByDouble { it.amount.toDouble() }
val result = list.first { it.status == "WAIT" }.amount + expiredSum
If you don't want to throw an exception if there are no elements with the status "WAIT", use firstOrNull() instead:
val expiredSum = list.filter { it.status == "EXPIRED" }.sumByDouble { it.amount.toDouble() }
val initialValue = list.firstOrNull { it.status == "WAIT" }?.amount ?: 0F
val result = initialValue + expiredSum
Actually, your code is not doing what you want
calculate the sum of all elements with the status EXPIRED (if they exist) and add to this sum amount of the first object with the type WAIT (if it exists)
It calculates the sum of all elements with the status EXPIRED (if they exist) and add to this sum amount of the first object with the type WAIT located after the last object with EXPIRED status (if it exists) OR amount of the object with index one (if it exist) if there were no elements with status EXPIRED:
println(getRestructuringAmountToPay(listOf(Test("EXPIRED", 1f), Test("WAIT", 1f), Test("EXPIRED", 1f)))) //will print 2.0, while following original description it should be 3.0
println(getRestructuringAmountToPay(listOf(Test("WAIT", 1f), Test("WAIT", 100f)))) //Will print 100.0, while following original description it should be 1.0
To get originally desired behavior in Kotlin-way you need to do the following:
if (list == null) return 0f //get rid of nullability
val (expired, waiting) = list.partition { it.status != "WAIT" } //split original list into respectful partitions
val sum = expired.map { it.amount }.sum() + (waiting.firstOrNull()?.amount ?: 0f) //do the calculations
I'am not sure I understand your solution but respectively to your goal this:
var sum = list.filter { it.status == "EXPIRED" }.sumByDouble { it.amount.toDouble() }
list.firstOrNull{ it.status == "WAIT" }?.let { sum+=it.amount}
println(sum)
Pretty is subjective - the code below is short but admittedly does not take advantage of the "sorted" nature of the collection
fun sum(data: List<Test>): Double {
val expiredSum = data.filter { it.status == "EXPIRED" }.sumByDouble { it.amount }
val waitSum = data.find { it.status == "WAIT" }?.amount ?: 0.0
return expiredSum + waitSum
}

find the average of pairs with the same first element. kotlin

I have a list of pairs in myPairs: List<Pair<String, Double>> and need to calculate the average of each set of pairs with the same first element.
I came up with this code. It finds separately the sum and the count for each group, then divides in by the count in a loop to find the average.
val myAverages = myPairs.groupingBy { it.first }.fold(0.0) { sum, element -> sum + element.second }.toMutableMap()
val myCounts = myPairs.groupingBy { it.first }.eachCount()
for ((myStr, count) in myCounts) {
myAverages[myStr] = myAverages[myStr]!!.div(count)
}
return myAverages
I wonder if there a more elegant/Kotlin-esque way to solve this by using aggregate or fold functions? My solution works but looks really ugly to me.
You can group your data set using groupBy function. Once you have the grouped map then you can map its values (List<Pair<String,Double>>) to the required average using the average function.
var mapOfAverages = myPairs.groupBy { it.first }
.mapValues { it.value.map { pair -> pair.second }.average() }
This will give you a map, where key is first element of your Pairs and value is the average of all the second elements for this particular key.

How to get min/max from ArrayList based on its object attribute values?

What I want to achieve is to get min/max attribute value of object from ArrayList<Object>. For example if Object has attribute weight(float), I want heaviest object from the list.
I've tried to implement Comparable to get max/min value but this returns same value for min and same for max for some reason. (I don't know if it works with floats)
val maxVal: Float = arrayList.max().floatVal1
val minVal: Float = arrayList.min().floatVal1
data class CustomObject(var val1: String, var floatVal1: Float , var floatVal2: Float?, var floatVal3: Float?, var floatVal4: Float?): Comparable<CustomObject>{
override fun compareTo(other: CustomObject) = (floatVal1 - other.floatVal1).toInt()
}
That specific question from duplicate post does not show me how to get max/min value based on Float. That's the problem. If I want to modify Comparator it accepts only Int. And i cant use that stream feature because my app is for API 23+ not 24+
I think you're looking for minBy and maxBy:
val minObject: CustomObject? = arrayList.minBy { it.floatVal1 }
val maxObject: CustomObject? = arrayList.maxBy { it.floatVal1 }
val maxObj: Object? = arrayList.maxByOrNull { it.floatVal1 }
val minObj: Object? = arrayList.minByOrNull { it.floatVal2 }
maxBy, minBy are deprecated since Kotlin 1.4
This return non-null types:
val max = list.maxOf { it.value }
val min = list.minOf { it.value }
Below Code returns Max value of your parameter in list of objects.
Ex)100 is max marks obtained all students
list.maxOf { it.yourParameter } // Returns Max value of yourParameter value in list of objects
Below Code returns Object of Max value of your parameter in list of objects.
Ex)Student object who got 100 marks
list.maxBy { it.yourParameter } // Returns Object of Max of yourParameter value in list of objects

Difference between fold and reduce in Kotlin, When to use which?

I am pretty confused with both functions fold() and reduce() in Kotlin, can anyone give me a concrete example that distinguishes both of them?
fold takes an initial value, and the first invocation of the lambda you pass to it will receive that initial value and the first element of the collection as parameters.
For example, take the following code that calculates the sum of a list of integers:
listOf(1, 2, 3).fold(0) { sum, element -> sum + element }
The first call to the lambda will be with parameters 0 and 1.
Having the ability to pass in an initial value is useful if you have to provide some sort of default value or parameter for your operation. For example, if you were looking for the maximum value inside a list, but for some reason want to return at least 10, you could do the following:
listOf(1, 6, 4).fold(10) { max, element ->
if (element > max) element else max
}
reduce doesn't take an initial value, but instead starts with the first element of the collection as the accumulator (called sum in the following example).
For example, let's do a sum of integers again:
listOf(1, 2, 3).reduce { sum, element -> sum + element }
The first call to the lambda here will be with parameters 1 and 2.
You can use reduce when your operation does not depend on any values other than those in the collection you're applying it to.
The major functional difference I would call out (which is mentioned in the comments on the other answer, but may be hard to understand) is that reduce will throw an exception if performed on an empty collection.
listOf<Int>().reduce { x, y -> x + y }
// java.lang.UnsupportedOperationException: Empty collection can't be reduced.
This is because .reduce doesn't know what value to return in the event of "no data".
Contrast this with .fold, which requires you to provide a "starting value", which will be the default value in the event of an empty collection:
val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)
So, even if you don't want to aggregate your collection down to a single element of a different (non-related) type (which only .fold will let you do), if your starting collection may be empty then you must either check your collection size first and then .reduce, or just use .fold
val collection: List<Int> = // collection of unknown size
val result1 = if (collection.isEmpty()) 0
else collection.reduce { x, y -> x + y }
val result2 = collection.fold(0) { x, y -> x + y }
assertEquals(result1, result2)
Another difference that none of the other answers mentioned is the following:
The result of a reduce operation will always be of the same type (or a super type) as the data that is being reduced.
We can see that from the definition of the reduce method:
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
}
return accumulator
}
On the other hand, the result of a fold operation can be anything, because there are no restrictions when it comes to setting up the initial value.
So, for example, let us say that we have a string that contains letters and digits. We want to calculate the sum of all the digits.
We can easily do that with fold:
val string = "1a2b3"
val result: Int = string.fold(0, { currentSum: Int, char: Char ->
if (char.isDigit())
currentSum + Character.getNumericValue(char)
else currentSum
})
//result is equal to 6
reduce - The reduce() method transforms a given collection into a single result.
val numbers: List<Int> = listOf(1, 2, 3)
val sum: Int = numbers.reduce { acc, next -> acc + next }
//sum is 6 now.
fold - What would happen in the previous case of an empty list? Actually, there’s no right value to return, so reduce() throws a RuntimeException
In this case, fold is a handy tool. You can put an initial value by it -
val sum: Int = numbers.fold(0, { acc, next -> acc + next })
Here, we’ve provided initial value. In contrast, to reduce(), if the collection is empty, the initial value will be returned which will prevent you from the RuntimeException.
Simple Answer
Result of both reduce and fold is "a list of items will be transformed into a single item".
In case of fold,we provide 1 extra parameter apart from list but in case of reduce,only items in list will be considered.
Fold
listOf("AC","Fridge").fold("stabilizer") { freeGift, itemBought -> freeGift + itemBought }
//output: stabilizerACFridge
In above case,think as AC,fridge bought from store & they give stabilizer as gift(this will be the parameter passed in the fold).so,you get all 3 items together.Please note that freeGift will be available only once i.e for the first iteration.
Reduce
In case of reduce,we get items in list as parameters and can perform required transformations on it.
listOf("AC","Fridge").reduce { itemBought1, itemBought2 -> itemBought1 + itemBought2 }
//output: ACFridge
The difference between the two functions is that fold() takes an initial value and uses it as the accumulated value on the first step, whereas the first step of reduce() uses the first and the second elements as operation arguments on the first step.