Kotlin sort hashmap in descending order - kotlin

I have val myHashMap = HashMap<String, MutableList<TestItem>>(), hashmap key value is formatted date as a string for example 20-06-2018 how can I sort this hashMap in descending order?
expected result:
22-06-2018 : []
21-06-2018 : []
20-06-2018 : []
I use this code to sort it, but result is in ascending order:
val sortedMap = myHashMap.toSortedMap(compareBy { it })

You can use compareByDescending:
val sortedMap = myHashMap.toSortedMap(compareByDescending { it })

The reason you get the result in ascending order is because (from the values you presented) all dates have month=6 and year=2018. If there are various dates then if you simply do compareByDescending the result will be wrong. Consider these dates:
21-05-2018, 22-4-2018. If you sort descending you will get 1st 22-04-2018!
What you need to do is convert the dates in yyyy-MM-dd and then sort descending:
fun convertDate(d: String): String {
val array = d.split("-")
return array[2] + array[1] + array[0]
}
val sortedMap = myHashMap.toSortedMap(compareByDescending { convertDate(it) })
One more thing: your dates must have 2 digits for month and day and 4 digits for year, dates like 2-5-2018 will give wrong result.
Last edit: no need for - in the concatenation.

This worked for me.
val sortedMap = myHashMap.toSortedMap(reverseOrder())
Reference: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.comparisons/reverse-order.html.

Related

Descending order ZoneDateTime in list kotlin

I have list of ZoneDateTime. I want to order by descending order. I didn't find the solution. Can some one guide me.
NearestResult(day=2020-05-09T20:09:03+01:00, event=xyz)
NearestResult(day=2020-05-09T09:15:15+01:00, event=abc)
NearestResult(day=2020-05-09T23:15:15+01:00, event=qwe)
NearestResult(day=2020-05-09T14:00:40+01:00, event=aks)
NearestResult.kt
data class NearestResult(
val day: ZonedDateTime,
val event: String
)
I tried some code but it's not working
lis.groupBy { it.day }
It giving me same above order.
Expected Output
NearestResult(day=2020-05-09T23:15:15+01:00, event=qwe)
NearestResult(day=2020-05-09T20:09:03+01:00, event=xyz)
NearestResult(day=2020-05-09T14:00:40+01:00, event=aks)
NearestResult(day=2020-05-09T09:15:15+01:00, event=abc)
Can somone guide me. Many Thanks
val desc = compareByDescending<NearestResult>{
it.day
}
val asc = compareBy<NearestResult>{
it.day
}
val sortedList = list.sortedWith(desc)
println(sortedList)
//or
list.sortedByDescending{ it.day }
list.sortedBy { it.day }.reversed()

Extend Groupby to include multiply aggregation

I implemented a groupby function which groups columns based on a particular aggregation successfully. The issue is I am using a argument for chosen columns and aggregation as Map[String,String] which means multiple aggregations cannot be performed on one column. for example sum, mean and max all on one column.
below is what works soo far:
groupByFunction(input, Map("someSignal" -> "mean"))
def groupByFunction(dataframeDummy: DataFrame,
columnsWithOperation: Map[String,String],
someSession: String = "sessionId",
someSignal: String = "signalName"): DataFrame = {
dataframeDummy
.groupBy(
col(someSession),
col(someSignal)
).agg(columnsWithOperation)
}
Upon looking into it a bit more, the agg function can take a list of columns like below
userData
.groupBy(
window(
(col(timeStampColumnName) / lit(millisSecondsPerSecond)).cast(TimestampType),
timeWindowInS.toString.concat(" seconds")
),
col(sessionColumnName),
col(signalColumnName)
).agg(
mean("physicalSignalValue"),
sum("physicalSignalValue")).show()
So I decided to try to manipulate the input to look like that, below is how I did it:
val signalIdColumn = columnsWithOperation.toSeq.flatMap { case (key, list) => list.map(key -> _) }
val result = signalIdColumn.map(tuple =>
if (tuple._2 == "mean")
mean(tuple._1)
else if (tuple._2 == "sum")
sum(tuple._1)
else if (tuple._2 == "max")
max(tuple._1))
Now I have a list of columns, which is still a problem for agg funciton.
I was able to solve it using a sequence of tuples like this Seq[(String, String)] instead of Map[String,String]
def groupByFunction(dataframeDummy: DataFrame,
columnsWithOperation: Seq[(String, String)],
someSession: String = "sessionId",
someSignal: String = "signalName"): DataFrame = {
dataframeDummy
.groupBy(
col(someSession),
col(someSignal)
).agg(columnsWithOperation)
and then with the information
from below post:
https://stackoverflow.com/a/34955432/2091294
userData
.groupBy(
col(someSession),
col(someSignal)
).agg(columnsWithOperation.head, columnsWithOperation.tail: _*)

Count consecutive duplicate values in ArrayList (Kotlin)

I would like to determine the number of consecutive duplicate Strings in an ArrayList in Kotlin.
What I have is something along the lines of:
val array: ArrayList<String> = arrayListOf("training", "training", "assessment", "training", "assessment", "assessment")
Where the output I want is something that counts the consecutive duplicate elements like:
[["training", "2"], ["assessment", "1"], ["training", "1"], ["assessment", "2"] or something simpler/cleaner.
I have found a similar solution in Python Counting consecutive duplicates of strings from a list. But I am looking for a Kotlin version. Thanks.
You could manually build the list, like this:
fun count(values: List<String>): List<Group> {
val groups = mutableListOf<Group>()
values.forEach {
val last = groups.lastOrNull()
if (last?.value == it) {
last.count++
} else {
groups.add(Group(it, 1))
}
}
return groups
}
data class Group(val value: String, var count: Int)
This results in:
[Group(value=training, count=2), Group(value=assessment, count=1), Group(value=training, count=1), Group(value=assessment, count=2)]

How to get max double in list?? With only one output, using Kotlin

I have tried using .maxBy .max() and collection.Max and I have only been able to print with it stating every element is max
val fileName = "src/products.txt"
var products = HashMap<Int, Pair<String, Double>>()
var inputFD = File(fileName).forEachLine {
var pieces = it.split(",")
println("Item# Description Price")
println("----- ------------- ------")
for ( (pro,ducts) in products.toSortedMap() ) {
var pax = mutableListOf(ducts).maxBy { it -> it.second }
var highest = listOf<Double>(ducts.second).max()
println("The highest priced record is ${highest}")
}
the file is set up like this (111, shoe, 9.99)
output looks like this
The highest priced record is [(pants, 89.99)]
The highest priced record is [(shoes, 49.99)]
You are trying to print the value within the for-loop, hence it is printing it for every product. Also the variable is initialized everytime in the loop, so every value would be max.
Here is the right approach. Note that you can solve it without using mutable variables.
val fileName = "src/products.txt"
val products = File(fileName).readLines() //read all lines from file to a list
.map { it.split(",") } // map it to list of list of strings split by comma
.map { it[0] to it[1].toDouble() } // map each product to its double value in a Pair
.toMap() // convert list of Pairs to a Map
println("Item# Description Price")
println("----- ------------- ------")
products.keys.forEachIndexed { index, desc ->
println("$index\t$desc\t${products[desc]}")
}
println("The highest priced record is ${products.maxBy { it.value }}")

Kotlin: Find Max Date list of lists

In kotlin consider:
data class classA (
field1
field2
....
classBlst:List<classB>
)
data class classB (
field3
field4
...
dateField:String
)
The problem is to loop thru List, find the maximum dateField in classBlst, and return the corresponding field3 for that item. The dateField is a string and may contain nulls and also bad dates so need to try..catch.
I can build a list with all max dates and then do a second iteration on that list to find max. I can do that using iterators but looking for any lambda functional way of doing the same. Sorry new to all this.
Given:
data class ClassA(val list: List<ClassB>)
data class ClassB(val field3: Int, val dateField: String? = null)
You could get the latest date using mapNotNull where you'll format your date and return null if you get an exception.
Then maxBy on the field containing the formatted date in you new object created in the previous mapNotNull
I've choosed to use a Pair since it look like you only want a filter and don't want to keep the newly created object. But if that not the case consider creating a new class containing all the information needed.
val a = ClassA(
listOf(
ClassB(0, "24"),
ClassB(1, "24/03/1987"),
ClassB(2),
ClassB(3, "24/03/2024")
)
)
val res = a.list
.mapNotNull {
val dateFormater = DateTimeFormatter.ofPattern("dd/MM/yyyy")
try {
Pair(it.field3, LocalDate.parse(it.dateField, dateFormater))
} catch (e: Exception) {
null
}
}
.maxBy { it.second }