What's the fastest/simplest way to calculate a moving Average in Kotlin? - kotlin

I can think on some dirty ways to calculate a moving average on Kotlin, but I'm not sure which one is the best. I know that kotlin has a lot of interesting features to work with collections and list. What do you think is the most efficient (or simplest) way to calculate a moving average?

Kotlin 1.2 will introduce a sliding window which you can combine with average obviously.
val data = listOf(1,2,5,6,2,7,8,5,9)
// 3 "period" moving average
val movingAverage = data.windowed(3,1,List<Int>::average)
// OR
val movingAverage = data.windowed(3,1) { it.average() }
Until then you would have to introduce your own sliding sequence.
class SlidingSequence<out T>(val source: Iterable<T>,
val slideSize: Int,
val slideStep: Int) : Sequence<List<T>> {
override fun iterator(): Iterator<List<T>> = object : AbstractIterator<List<T>>() {
private val iterator = if (slideSize > 0) source.iterator() else emptyList<T>().iterator()
private var buffer = listOf<T>()
override fun computeNext() = when {
iterator.hasNext() -> {
buffer = buffer.drop(slideStep).let {
it + iterator.asSequence().take(slideSize - it.size)
}
setNext(buffer)
}
else -> done()
}
}
}
fun <T> Iterable<T>.windowed(size: Int,
step: Int = 1): Sequence<List<T>> {
return SlidingSequence(this, size, step)
}
// and then you can do
val data = listOf(1,2,5,6,2,7,8,5,9)
// 3 "period" moving average
val movingAverage = data.windowed(3).map(List<Int>::average)
PS. I haven't looked at the code of Kotlin 1.2 windowed implementation, but since the function takes an immediate transform, I'm guessing the result is not lazy, where in the self implemented case above it's a lazy result, so you need to actually enumerate the sequence with something like .toList() to get the actual values.

Another one-line given period > 0 is:
data?.takeLast(period)?.reduce { v, d -> v + d}?: 0 / period
This also works if the data is empty or null due to takeLast() `s behaviour.

Related

How to find specific word in objects past 6 months and categories them week by week?

I'm new to Kotlin and trying to figure out how I can do the best way. I have an api call that I call and I convert the response to a list of objects:
data class JobAd(
val published: LocalDate?,
val title: String?,
val jobtitle: String?,
val description: String?
)
On the api call, I search for all job ads that are from today and back in time of 6 months. For example I get all objects which is from LocalDate.now() and 6 months back LocalDate).now().minusMonths(6). I want to iterate through all the objects and see if 2 random words (java and kotlin) are contained in the object. I want to check either title, jobtitle or description contain the word java or kotlin. I only need one hit of the word java or kotlin in these properties, if title contain java or kotlin, add it to list and check next object. If not title contain the words and either jobtitle, but description does it, add it to the list and check next object. and add it to a list based on which week it is.
I want the output to be like this:
(2022) Week 12 -> Java: 0, Kotlin: 1
(2022) Week 11 -> Java: 0, Kotlin: 0 (If some weeks does not have hit, i want to show to too)
...
(2021) Week 52 -> Java: 1, Kotlin: 2
This is my code so far:
private fun findAdsBasedOnKeyWords(jobAds: MutableList<JobAd>, keywords: List<String>, from: LocalDate, to: LocalDate): MutableMap<Any, MutableMap<String, Any>> {
val resultMap = mutableMapOf<Any, MutableMap<String, Any>>()
val counter = mutableMapOf<String, Any>() //Meta data
for (jobAd: JobAd in jobAds) {
for (keyword: String in keywords) {
val weekNumber = DateParser.getWeekNumber(jobAd.published!!)
// Initialize placeholder data, to fill even empty weeks
resultMap.putIfAbsent(weekNumber, emptyMapOfKeywords(keywords, jobAd.published))
// Validate keyword exist in job ad
val contains = jobAd.toString().lowercase()
.contains(keyword.lowercase()) //Can be an issue if the toString gets overridden
if (contains) {
counter.putIfAbsent(keyword, 0)
counter.compute(keyword) { _, v -> v.toString().toInt() + 1 }
resultMap[weekNumber]!!.compute(keyword) { _, v -> v.toString().toInt() + 1 }
}
}
}
resultMap["total"] = counter
resultMap["period"] = mutableMapOf("from" to from, "to" to to)
logger.info("[{}] matches found", counter)
return resultMap
}
//Helper method to generate placeholder data
private fun emptyMapOfKeywords(keywords: List<String>, published: LocalDate): MutableMap<String, Any> {
val keywordMap = mutableMapOf<String, Any>()
for (keyword in keywords) {
keywordMap.putIfAbsent(keyword, 0)
}
keywordMap.putIfAbsent("from", DateParser.startOfWeekDate(published))//Monday of the week
keywordMap.putIfAbsent("to", DateParser.endOfWeekDate(published))//Sunday of the week
return keywordMap
}
Is there any way to do it better or optimize it and please add comment for why.
It's a pretty extreme anti-pattern to use Maps to hold various types of data that you need to inspect. That's trying to force a strongly typed language to behave like a weakly typed language, losing all the protection you get from using types.
Maps are appropriate when the keys are something you don't know at compile time and you know you'll need to look up items by their keys at runtime.
So instead of a MutableMap<Any, MutableMap<String, Any>> return value, you should create classes for holding results. From what I can tell, you want to return a series of line items for every week in the input range, so you can create a class like this to represent a line item, and then return a simple list of them from your function. You are currently also returning the range, but I don't see what you're using it for so I left it out.
You're working with a week of a year a lot, so I think it will also be helpful to have a class to represent that, along with a couple of functions to help convert from LocalDate.
data class LocalWeek(val year: Int, val week: Int)
fun LocalDate.toLocalWeek() = LocalWeek(year, get(IsoFields.WEEK_OF_WEEK_BASED_YEAR))
/** Gets every week represented in a range of dates. */
fun ClosedRange<LocalDate>.toLocalWeeks() = sequence {
var date = start
val lastExclusive = endInclusive + Period.ofWeeks(1)
while (date < lastExclusive ) {
yield(date.toLocalWeek())
date += Period.ofWeeks(1)
}
}
data class JobAdsSearchLineItem(
val localWeek: LocalWeek,
val keywordHitCountsByKeyword: Map<String, Int>
) {
fun toReadableString() =
"(${localWeek.year}) Week ${localWeek.week} -> " +
keywordHitCountsByKeyword.entries
.joinToString { (word, count) -> "$word: $count" }
}
Using toString() is fragile, like you mentioned in your code comments. I would create a helper function like this to evaluate whether a term is found:
fun JobAd.containsIgnoreCase(str: String): Boolean {
val value = str.lowercase()
return title.orEmpty().lowercase().contains(value)
|| jobtitle.orEmpty().lowercase().contains(value)
|| description.orEmpty().lowercase().contains(value)
}
Since you're using !! on your published date, I'm assuming these values don't need to be nullable. It would be much easier to work with if you make the property non-nullable:
data class JobAd(
val published: LocalDate,
val title: String?,
val jobtitle: String?,
val description: String?
)
Then your search function can be written like this:
private fun findAdsBasedOnKeyWords(
jobAds: List<JobAd>,
keywords: List<String>,
from: LocalDate,
to: LocalDate
): List<JobAdsSearchLineItem> {
// Initialize empty results holders representing every week in the range
// Use an outer map here because we need to keep retrieving the inner maps by
// the week when iterating the input below.
val results = mutableMapOf<LocalWeek, MutableMap<String, Int>>()
for (localWeek in (from..to).toLocalWeeks()) {
results[localWeek] = mutableMapOf<String, Int>().apply {
for (keyword in keywords) {
put(keyword, 0)
}
}
}
for (jobAd in jobAds) {
val weekResults = results[jobAd.published.toLocalWeek()] ?: continue
for (keyword in keywords) {
if (jobAd.containsIgnoreCase(keyword)) {
weekResults[keyword] = weekResults.getValue(keyword) + 1
}
}
}
return results.entries.map { JobAdsSearchLineItem(it.key, it.value) }
}
And to use it you can call this function and use the toReadableString() function to help generate your output from the list of results.

Kotlin: Pass ranges in function as arguments

Hello is it possible to pass range in Kotlin function just like in python?
I've just started learning Kotlin but I am a little bit stuck
I wish i could pass somethind like
my_gauge = Gauge('test_name',1..200, 201..300, and etc.)
for example I have a Gauge object which rotates on the base
class Gauge(val gauge_name: String,
val red_value: Float,
val orange_value: Float,
val yellow_value: Float,
val green_value: Float,
var current_value: Float,
val min_value: Float,
val max_value: Float) {
val gauge_green = 0xFF66C2A5.toInt()
val gauge_yellow = 0xFFFDD448.toInt()
val gauge_orange = 0xFFF5A947.toInt()
val gauge_red = 0xFFD53E4F.toInt()
val min_rotation: Int = 0;
val max_rotation: Int = 300;
val ratio = max_rotation / max_value;
fun calculate_rotation(): Int {
return (current_value * ratio).toInt()
}
fun get_color(): Int {
if (current_value >= red_value) {
return gauge_red
}
if (current_value > orange_value) {
return gauge_orange
}
if (current_value > yellow_value) {
return gauge_yellow
}
return gauge_green
}
}
I've just realized that it wont work with this data instead it will be better to build my logic around ranges
So my question is How to pass ranges as a param in class/function (instead of floats)
PS: The function get_colors is not correct I will fix it once I can pass ranges with when(current_value) statement
Yes, the type of a range produced by .. is ClosedRange<T>:
fun foo(floatRange: ClosedRange<Float>) {
println(floatRange.random())
}
// Usage:
foo(1f..10f)
For integer ranges, you may prefer IntRange over ClosedRange<Int> because it allows you to use it without the performance cost of boxing by using first and last instead of start and endInclusive. There is no unboxed version for other number types.
Try this in simple way, you can use range according to data type IntRange, FloatRange, LongRange etc.
fun foo(range: IntRange){
for (a in range){
println(a)
}
}
// call this function by
foo(1..10)

Taking sequence elements fulfilling a predicate then continuing from there in Kotlin

In Kotlin sequences have a takeWhile function that will let you take items as long as they adhere to a given predicate. What I'd like to do is take items according to that predicate, use them in some way, then alter the predicate and take the next "batch". So far I haven't really found a way of doing this purely with what sequences and iterators offer.
Following snippet of code illustrates the problem. The primeGenerator() function returns a Sequence of prime (Long) numbers. Suppose that I want to make lists with each list having prime numbers with the same number of digits. On creating each list I'd use it for some purpose. If the list conforms to what I was searching the iteration can end, otherwise move onto the next list.
val primeIt = primeGenerator().iterator()
var digits = 1
var next: Long? = null
val currentList = ArrayList<Long>()
while (digits < 4) {
next?.also { currentList.add(it) }
next = primeIt.next()
if (next.toString().length > digits) {
println("Primes with $digits: $currentList")
currentList.clear()
digits++
}
}
In this case it ends once the number of digits exceeds 3. This works fine, but I was wondering if there is some way to achieve the same with operations chained purely on the sequence or an iterator of it. Basically chunking the sequence but based on a predicate rather than a set size. The prime number example above is just for illustration, I'm after the general principle, not something that'd only work for this case.
There are no such functions in standard library for large (or infinite) sequences, but you may write such function by yourself (although it requires some extra code):
class BufferedIterator<T>(private val iterator: Iterator<T>) : Iterator<T> {
var current: T? = null
private set
var reachedEnd: Boolean = false
private set
override fun hasNext(): Boolean = iterator.hasNext().also { reachedEnd = !it }
override fun next(): T = iterator.next().also { current = it }
}
fun <T> Iterator<T>.buffered() = BufferedIterator(this)
fun <T> BufferedIterator<T>.takeWhile(predicate: (T) -> Boolean): List<T> {
val list = ArrayList<T>()
if (reachedEnd) return list
current?.let {
if (predicate(it)) list += it
}
while (hasNext()) {
val next = next()
if (predicate(next)) list += next
else break
}
return list
}
fun main() {
val sequence = sequence {
var next = 0
while (true) {
yield(next++)
}
}
val iter = sequence.iterator().buffered()
for (i in 0..3) {
println(iter.takeWhile { it.toString().length <= i })
}
}
With this approach you can easily work even with infinite sequences.
I believe there is a way to accomplish what you want using the standard library. Limit the sequence first and then groupBy the number of digits.
val Int.numberOfDigits
get() = this.toString().length
sequenceOf(1,22,333).takeWhile{ it.numberOfDigits < 3 }.groupBy{ it.numberOfDigits }.values
If you want to avoid the eager evaluation of groupBy you could use groupingBy instead and then reduce potentially leaving the accumulator blank.
ardenit's answer seems like the best reusable approach. Since taking "chunks" of a sequence requires some state it doesn't seem likely something easily done in a purely functional manner. Delegating the state to a separate class enveloping the sequence makes sense.
Here's a small snippet showing what I ended up using. This assumes the sequence will not be empty and is (technically) infinite or further results aren't requested at some point.
class ChunkedIterator<T>(seq: Sequence<T>) {
private val it = seq.iterator()
var next: T = it.next()
fun next(predicate: (T) -> Boolean): List<T> {
val result = ArrayList<T>();
while (predicate.invoke(next)) {
result.add(next)
next = it.next();
}
return result
}
}
one way you could achieve this is by getting an iterator from your your original sequence and then building a new sequence out of it for each "take" -
val itr = seq.iterator()
val batch1 = itr.asSequence().takeWhile { predicate1(it) }.toList()
val batch2 = itr.asSequence().takeWhile { predicate2(it) }.toList()

Traverse a list of filter to appy them

I have some filter on a list(10..1000).
I would like to have a list of function objects, traverse this list and apply that filter to (10..1000).
Maybe later choose some filters.
fun main(args: Array<String>) {
var sol = (10..1000).toList().filter(lastDigitIsLength ).filter(no7andNo1 ).filter(isEvenAndGreater1).filter(first2DigitsOddCrossSumLess10 ).filter(isPrime )
println("The number is $sol")
}
/* The functions exist
There are few ways to do that.
I've listed them in my example, along with some general comments.
// No need for varargs since Kotlin 1.3
fun main() {
// Prefer vals over vars
val sol = (10..1000).
asSequence().// Use asSequence instead of toList
filter { lastDigitIsLength(it) }. // Block
filter(::no7andNo1). // Method reference
toList()
println("The number is $sol")
}
// Don't know what it means, so lets just always return true
fun lastDigitIsLength(i: Int) = true // Short notation
fun no7andNo1(i: Int): Boolean {
return i % 10 == 7 || i % 10 == 1
}
Sorry, maybe I misunderstand your question. Do you want to apply a list of filters to list of ints? If so, it can be done like this:
fun filter(list: List<Int>, filters: List<(Int) -> Boolean>): List<Int> {
var result = list
for (filter in filters) {
result = result.filter(filter)
}
return result
}
so you can rewrite your function as:
fun main() {
val sol = filter((10..1000).toList(), listOf(::lastDigitIsLength, ::no7andNo1, ::isEvenAndGreater1))
println("The number is $sol")
}

Swap Function in Kotlin

is there any better way to write generic swap function in kotlin other than java way described in How to write a basic swap function in Java.
Is there any kotlin language feature which can make generic swap function more concise and intuitive?
No need a swap function in Kotlin at all. you can use the existing also function, for example:
var a = 1
var b = 2
a = b.also { b = a }
println(a) // print 2
println(b) // print 1
If you want to write some really scary code, you could have a function like this:
inline operator fun <T> T.invoke(dummy: () -> Unit): T {
dummy()
return this
}
That would allow you to write code like this
a = b { b = a }
Note that I do NOT recommend this. Just showing it's possible.
Edit: Thanks to #hotkey for his comment
I believe the code for swapping two variables is simple enough - not to try simplifying it any further.
The most elegant form of implementation IMHO is:
var a = 1
var b = 2
run { val temp = a; a = b; b = temp }
println(a) // print 2
println(b) // print 1
Benefits:
The intent is loud and clear. nobody would misunderstand this.
temp will not remain in the scope.
Kotlin encourages the use of immutable data when possible (such as using val instead of var). This greatly reduces the change for subtle bugs, since it's possible to reason more soundly about code if values don't change.
Swapping two values is very much the opposite of immutable data: Did I mean the value of a before or after the swap?
Consider rewriting your code in the following immutable way:
val a = 1
val b = 2
val (a2, b2) = b to a
This works by making use of destructuring declarations, along with the built-in to extension function that creates a Pair.
That is a good usage for with:
var a = 1
var b = 2
with(a) {
a = b
b = this
}
println(a) // 2
println(b) // 1
Very simple, fast and elegant solution:
var a = 1
var b = 2
val (b0, a0) = a swap b
a = a0
b = b0
infix fun <A> A.swap(second: A): Pair<A, A> = second to this
prefer a=b.apply {b=a} for swapping the elements.
If we want to perform some operation on the variable inside the lambda, then go for
a = b.also {someFun(it)}
If you're swapping array values in place, from a code readability perspective, it was helpful for me to add an extension function swapInPlace
fun <T> Array<T>.swapInPlace(i1: Int, i2: Int){
this[i1] = this[i2].also{ this[i2] = this[i1] }
}
fun main(){
val numbers = arrayOf(2, 1)
//This is easier for me to read...
numbers.swapInPlace(0, 1)
//Compared to this
numbers[0] = numbers[1].also{ numbers[1] = numbers[0] }
}
I have something interesting for all:
Why just numbers. We can swap anything with a generic class and a generic function
class Mutable<T>(var value: T) {
override fun toString() = value.toString()
/**
infix fun swapWith(other: Mutable<T>) {
value = other.value.also { other.value = value }
}
**/
}
fun <T> swap(num1: Mutable<T>, num2: Mutable<T>) {
num1.value = num2.value.also { num2.value = num1.value }
}
fun main() {
val num1 = Mutable(4)
val num2 = Mutable(6)
println("Before Swapping:-\n\tNumber#1 is: $num1\n\tNumber#2 is: $num2\n")
//calling way of class method is not like usual swap function
//num1 swapWith num2
//calling the actual swap function.
swap(num1, num2)
println("After Swapping:-\n\tNumber#1 is: $num1\n\tNumber#2 is: $num2\n")
}
class Mutable is a generic class here which can contain any type of data into it.
I overridden toString() method to directly accessing the value attribute by just calling the object.
fun swap is a true swap function for kotlin that gives you the call by reference's demo too.
operator swapWith also works as swap function, which is a part of Mutable class. I have commented that part because the calling way for the operator is not like the way we are used to with.
Output:
Before Swapping:-
Number#1 is: 4
Number#2 is: 6
After Swapping:-
Number#1 is: 6
Number#2 is: 4
I have different approach.
You can keep your two values in a Pair. Then you can do this:
fun <T> swap(pair: Pair<T, T>): Pair<T, T> {
return Pair(pair.second, pair.first)
}
and you use it like this:
var pairOfInts = Pair(1, 2)
println("first: ${pairOfInts.first}") // prints 1
println("second: ${pairOfInts.second}") // prints 2
pairOfInts = swap(pairOfInts)
println("first: ${pairOfInts.first}") //prints 2
println("second: ${pairOfInts.second}") //prints 1
In order to use Kotlin List you could create this kind of extension. It returns a copy of this list with elements at indices a and b swapped.
fun <T> List<T>.swap(a: Int, b: Int): List<T> = this
.toMutableList()
.also {
it[a] = this[b]
it[b] = this[a]
}
If you use an array, you can use this:
fun <T> Array<T>.swap(i: Int, j: Int) {
with(this[i]) {
this#swap[i] = this#swap[j]
this#swap[j] = this
}
}