Count consecutive duplicate values in ArrayList (Kotlin) - 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)]

Related

How to filter elements in one list by a property value not present in elements in another list?

I have the following code snippet
val cachedNews = listOf(News(9, "https://009"), News(8, "https://234"), News(7, "https://345"))
val freshNews = listOf(News(1, "https://123"), News(2, "https://234"), News(3, "https://345"))
val result = freshNews.filter {fresh -> filter(cachedNews, fresh)}
private fun filter(cached: List<News>, fresh: News): Boolean {
cached.forEach { cachedItem ->
if (cachedItem.url == fresh.url) return true
}
return false }
When the code runs if cachedItem.url == fresh.url the list is filtered and the result is a list where the urls of the two lists are identical. However when i reverse equality like so cachedItem.url != fresh.url the list is not filtered at all. The sequence of execution changes.
When using the == sign, the first item of freshNews is compared with the first Item of cachedNews after that the secondItem of freshNews is compared with secondItem of cachedNews and so on.
When I use the != sign the all items of freshNews are compared against only the firstItem of cachedNews ??
Am I missing something or is my code just wrong?
I'm not sure what the specific problem is because your approach is quite confusing. Your custom filter function is actually more like a contains function.
What might be useful is to:
Extract the cached URLs to a set
Filter the new results by URLs that are not in the set.
fun main() {
val cachedNews = listOf(News(9, "https://009"), News(8, "https://234"), News(7, "https://345"))
val freshNews = listOf(News(1, "https://123"), News(2, "https://234"), News(3, "https://345"))
val cachedUrls = cachedNews.map { it.url }.toSet()
val result = freshNews.filterNot { cachedUrls.contains(it.url) }
println(result)
}
Result:
[News(id=1, url=https://123)]

About binarySearch() of Kotlin List

I ran the examples in the official Kotlin documentation in the local Android Studio, and found that the results are different from what I expected, but I don’t know what is causing this?
data class Produce(
val name: String,
val price: Double
)
This is the data class I defined
val list2 = listOf(
Produce("AppCode", 52.0),
Produce("IDEA", 182.0),
Produce("VSCode", 2.75),
Produce("Eclipse", 1.75)
)
this is my source list
println(list2.sortedWith(compareBy<Produce> {
it.price
}.thenBy {
it.name
}))
The output on the console is:
[Produce(name=Eclipse, price=1.75), Produce(name=VSCode, price=2.75), Produce(name=AppCode, price=52.0), Produce(name=IDEA, price=182.0)]
I call binarySearch() like this
println("result: ${
list2.binarySearch(
Produce("AppCode", 52.0), compareBy<Produce> {
it.price
}.thenBy {
it.name
}
)
}")
I think the result should be 2, but it is 0
result: 0
I don't know why it turned out like this. Plase help me . thanks a lot
sortedWith() does not modify the list, it returns a new, sorted collection. When calling list2.binarySearch() you still search through original, unsorted list.
You need to either do something like:
list2.sortedWith().binarySearch()
Or create your list with mutableListOf() and then use sort() which sorts in-place.
Broot is right. You need to pass the sorted list to the binarySearch() function. To clarify in code:
val comparator = compareBy<Produce> { it.price }.thenBy { it.name }
val sorted = list2.sortedWith(comparator)
println(sorted.joinToString("\n"))
val foundIndex = sorted.binarySearch(Produce("AppCode", 52.0), comparator)
println("Found at: $foundIndex")
Result:
Produce(name=Eclipse, price=1.75)
Produce(name=VSCode, price=2.75)
Produce(name=AppCode, price=52.0)
Produce(name=IDEA, price=182.0)
Found at: 2

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: _*)

Return single value from forEach kotlin

Im wondering, whats the best way to accomplish following:
val asd = listOfStuff.forEach {
if ( it.name == name ) return it
}
so that asd will be first value of list where it.name equals name
I know there is multiple ways, but since im using kotlin, why not go kotlin way..
Im just having hard time finding right words to google this problem.
You can do it with firstOrNull like this:
val asd = listOfStuff.firstOrNull { it.name == name }
You can find elements matching a given condition, like this:
fun main() {
val listOfStuff = listOf("1", "2", "3", "4", "5")
val asd = listOfStuff.find { it == "1"}
print(asd)
}
Output will just be 1.
Note that this will find the first value matching the condition or return null if the element is cannot be found, so the answer given by #forpas is better if you don't know for sure the element is present.
Have you tried using the Array.find function?
You can find more information here: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/index.html
In your example you should get the element with:
val asd = listOfStuff.find(name)
I'm not sure how your array looks like. But it seems like you have multiple objects with properties (name). Then you probably need to do something like:
val result: asd? = listOfStuff.flatMap { it.name }.firstOrNull { it.name == "name" }

How to convert EnumSet<A> to Set<B>

I have an enum class thats something like this:
enum class SomeType(val id: String) {
TYPE1("A"),
TYPE2("B"),
TYPE3("C"),
TYPE4("D")
}
Now, I need to filter a list of Something which has a String that's stated in SomeType enum. So Basically I have something like this:
class Something(val id: String)
// where the value of id is one of the value of the SomeType's id
I have a list of Something like so:
val somethingList = arrayListOf<Something>(
Something("A"),
Something("B"),
Something("A"),
Something("C"),
Something("D"),
Something("A"),
Something("D")
)
Now I need to filter that somethingList to by the given EnumSet<SomeType>.
So if I have a:
val someTypeSet = EnumSet.of(SomeType.Type3, SomeType.Type2)
the resulting filtered List should be,
val filteredList = arrayListOf<Something>(
Something("B"),
Something("C")
)
My idea is to convert the someTypeSet to a Set<String> and just do something like:
Set<String> setOfSomeTypeIds = convertToSet(someTypeSet)
val filteredList = somethingList.filter { something ->
setOfSomeTypeIds.contains(something.id)
}
Can someone guide me how to convert an EnumSet to a Set of its value?
I also explained the whole process just in case there is a better solution to the problem above.
Anything will be appreciated.
Thanks in advance.
You can use map on any collection to transform it to a new collection with the desired values... i.e. someTypeSet.map { it.id } will already return you a list of string. If you really want to have a Set you can also use something like mapTo. Regarding the filter that might also be simplifiable using the in-keyword, e.g.: somethingList.filter { it.id in setOfSomeTypeIds }.
So summarized:
val setOfSomeTypeIds = someTypeSet.map { it.id }
val filteredList = somethingList.filter { it.id in setOfSomeTypeIds }
You can use the map function after you filter the relevant types.
val filteredSomethings:List<Something> = someTypeSet.filter { something ->
setOfSomeTypeIds.contains(something.id) }.map { Something(it.id) }
It will return a List of Something with the relevant Ids.