Kotlin Exposed Sum on condition (CaseWhenElse) - kotlin

I have a table with data structure like :
id type cityName regDate
1249 0 City1 2019-10-01
I want to get result output of unique cities and the number of registrations in it per month as a list of data class objects of
data class NewClientsNumberCityMonth(
val cityName: String = "",
val januaryNewClientsNumber :Int = 0,
val februaryNewClientsNumber :Int = 0,
val marchNewClientsNumber :Int = 0,
val aprilNewClientsNumber :Int = 0,
val mayNewClientsNumber :Int = 0,
val juneNewClientsNumber :Int = 0,
val julyNewClientsNumber :Int = 0,
val augustNewClientsNumber :Int = 0,
val septemberNewClientsNumber :Int = 0,
val octoberNewClientsNumber :Int = 0,
val novemberNewClientsNumber :Int = 0,
val decemberNewClientsNumber :Int = 0
val total :Int = 0
)
and use this objects as the strings to fill the table (we dont know the number of unique cities),
result should be like :
City1 5 8 3 1 2 1 4 1 2 1 0 0
City2 69 23 7 5 3 10 24 14 12 23 25 10
...
im trying this
val tempMutList = mutableListOf<NewClientsNumberCityMonthModel>()
transaction(Connection.TRANSACTION_SERIALIZABLE, 2) {
addLogger(StdOutSqlLogger)
ClientsDataExposed
.slice(ClientsDataExposed.cityName)
.selectAll()
.groupBy(ClientsDataExposed.cityName)
.map { it[ClientsDataExposed.cityName] }
.toList().forEach {
val regsInCity = ClientsDataExposed
.slice(
ClientsDataExposed.id,
ClientsDataExposed.cityName,
ClientsDataExposed.type,
ClientsDataExposed.regDate,
ClientsDataExposed.regDate.month()
)
.selectAll()
.andWhere { ClientsDataExposed.cityName.eq(it) }
.andWhere {
ClientsDataExposed.regDate.between(
Date.valueOf("2019-01-01".toString()),
Date.valueOf("2020-01-01".toString())
)
}
.andWhere {
(ClientsDataExposed.type.inList(contracterTypeSelectedCheckboxes.filterValues { it }.keys.toList())) and (ClientsDataExposed.cityName.inList(
citiesSelectedChekboxes.filterValues { it }.keys.toList()
))
}
.map { it[ClientsDataExposed.regDate.month()] }
.toList()
val cityClientsPerMonth = NewClientsNumberCityMonthModel(
it,
regsInCity.count { it == 1 },
regsInCity.count { it == 2 },
regsInCity.count { it == 3 },
regsInCity.count { it == 4 },
regsInCity.count { it == 5 },
regsInCity.count { it == 6 },
regsInCity.count { it == 7 },
regsInCity.count { it == 8 },
regsInCity.count { it == 9 },
regsInCity.count { it == 10 },
regsInCity.count { it == 11 },
regsInCity.count { it == 12 },
regsInCity.count()
)
tempMutList.add(cityClientsPerMonth)
//obj of dataclass
}
viewTableTabOfnewClientsNumberCityMonth.value = tempMutList.map { it }
}
i know, that i should use Sum() and CaseWhenElse , like here , with check on
ClientsDataExposed.regDate.month()
which gives a month number (1-12), to assign the sum() result to my data class property, but i can't find any examples of CaseWhenElse syntax and i can't figure out it myself,
or may be there is another way of getting it whithout using of CaseWhenElse ?

Please check that code:
val monthExpr = ClientsDataExposed.regDate.month()
fun sumByMonth(monthNum: Int) = Expression.build {
val caseExpr = case().
When(monthExpr eq intLiteral(monthNum), intLiteral(1)).
Else(intLiteral(0))
Sum(caseExpr, IntegerColumnType())
}
val janSumExp = sumByMonth(1)
val febSumExp = sumByMonth(2)
ClientsDataExposed.
slice(ClientsDataExposed.cityName, janSumExp, febSumExp).
selectAll().
groupBy(ClientsDataExposed.id).map {
val janSum = it[janSumExp]
val febSum = it[febSumExp]
...
}

Related

Fill missing data in a linear model

I have the following val list = listOf(1, 2, 3, null, null, 6, 7) I'd like to fill the null value for the following result: listOf(1, 2, 3, 4, 5, 6, 7)
I couldn't find any method doing this in Kotlin, do you guys have an idea?
EDIT: I'm adding more details, the list will always have a beginning element and an ending element (ie no list as listOf(null, 2 ,3) or listOf(1, 2, null)) I preprocess this.
In my example I gave Integer element but it could be Float or Double
I've manage to do a simple function that could interpolate. There is room for improvement.
private fun Double.format(): String = DecimalFormat("#.##").format(this)
private fun List<*>.findNonNullIndex(currentIndex: Int, ascending: Boolean = true): Int {
for (i in currentIndex..lastIndex step if(ascending) 1 else -1) {
if(getOrNull(i) != null) return i
}
return currentIndex
}
fun interpolate(list: MutableList<Double>) {
println("initial : $list")
list.forEachIndexed { index, i ->
if(i == null) {
val nonNullIndex = list.findNonNullIndex(index)
val difference = list[nonNullIndex]?.minus(list[index-1] ?: return) ?: return
val coefficient = difference.div((nonNullIndex - index) + 1)
for(j in index until nonNullIndex) {
list[j] = (list[j-1]?.plus(coefficient))?.format()?.toDouble()
}
}
}
println("result: $list")
}
interpolate(mutableListOf(1.0, null, null, null, 1.4, null, 1.5, 1.7))
link: https://pl.kotl.in/HcqoB8qFL
Try this
inline fun <T>List<T?>.replaceIfNull(block:(T) -> T) : List<T>{
val temp = mutableListOf<T>()
for((index, element) in this.withIndex()){
if(element == null){
temp.add(block(this[index - 1] ?: temp[index - 1]))
} else {
temp.add(element)
}
}
return temp
}
fun main() {
val list = listOf(1, 2, 3, null, null, 6, 7)
val foo = list.replaceIfNull { nonNullValue ->
nonNullValue + 1
}
println(foo) // [1, 2, 3, 4, 5, 6, 7]
}
EDIT
Linear Model
fun <T:Number>List<T?>.interpolate() : List<Double> {
val temp = mutableListOf<Double>()
var nullCounter = 0
this.forEach { element ->
if(element != null){
val formatedElement = element.format()
temp.add(formatedElement)
if(nullCounter > 0){
var difference = (formatedElement - temp[temp.size - 2]) / (nullCounter + 1)
for(i in 0..nullCounter - 1){
val newElement = (temp[temp.size - 2] + difference).format()
temp.add((temp.size - 1), newElement)
}
}
nullCounter = 0
}
element ?: nullCounter++
}
return temp
}
test: https://pl.kotl.in/rpbDZ8zkq
There's no way on how to decide what number you want to replace with null.
Considering what if listOf(1, null, null) or listOf(null, 2, null).
If you know exactly what a list needs to be, you might use IntProgression or IntRange instead.
// 1, 2, 3, 4, 5, 6, 7
val list1 = IntRange(1, 7).toList()
// 1, 3, 5, 7
val list1 = IntProgression(1, 7, 2).toList()

How to create list/set of functions in Kotlin

I have this code in java
// set of functions to transform int to String
private static final Set<IntFunction<String>> RULE_SET = new LinkedHashSet<IntFunction<String>>() {{
add(i -> i % 2 == 0 ? "buzz" : "");
add(i -> i % 3 == 0 ? "fizz" : "");
add(i -> i % 4 == 0 ? "2gis" : "");
}};
//client code
private String transformNum(int num) {
final String transformed = RULE_SET.stream()
.map(rule -> rule.apply(num))
.collect(Collectors.joining());
return transformed.length() == 0 ? String.valueOf(num) : transformed;
}
and now I'm trying to transform it to Kotlin.
But I feel that there is much simpler and easier way to create collection of functions, could you please advise? There is what I have now. Works, but looks weird for me, like I'm using Java in Kotlin, but not Kotlin itself. :)
private val rules = setOf<IntFunction<String>>(
IntFunction { i: Int -> if (i % 2 == 0) "buzz" else "" },
IntFunction { i: Int -> if (i % 3 == 0) "fizz" else "" },
IntFunction { i: Int -> if (i % 4 == 0) "2gis" else "" }
)
private fun transformNum(num: Int): String {
val transformed = rules.joinToString("") { rule: IntFunction<String> ->
rule.apply(num)
}
return if (transformed.isEmpty()) num.toString() else transformed
}
maybe this?
val ss = setOf<(Int) -> String>(
{ i -> if (i%2 == 0) "apple" else ""},
{ i -> if (i%3 == 0) "banana" else ""},
{ i -> if (i%4 == 0) "cherry" else ""}
)
private fun transform(num: Int): String =
ss.joinToString(""){ it(num) }
.let {
if (it.isEmpty()) num.toString() else it
}
Maybe this?
private val rules = setOf(
{ i : Int -> if (i % 2 == 0) "buzz" else "" },
{ i : Int -> if (i % 3 == 0) "fizz" else "" },
{ i : Int -> if (i % 4 == 0) "2gis" else "" }
)
and
private fun transformNum(num: Int) = rules.joinToString("") {it(num)}.run {
if (isEmpty()) num.toString() else this
}

Setter not assigning value in Kotlin

I am trying to do a temperature program, which outputs the lowest temperature from three cities provided. If the temperature of one of three cities is above + 57 or below -92 all three cities will have set default values which are (+5 Moscow, +20 Hanoi , 30 for Dubai)
However providing those numbers 20,100,35 in readLine doesn't work.
This is how City class looks like:
class City(val name: String) {
var degrees: Int = 0
set(value) {
field =
if (value > 57 || -92 > value) {
when (this.name) {
"Dubai" -> 30
"Moscow" -> 5
"Hanoi" -> 20
else -> 0
}
} else {
value
}
}}
And in my main I have:
val first = readLine()!!.toInt()
val second = readLine()!!.toInt()
val third = readLine()!!.toInt()
val firstCity = City("Dubai")
val secondCity = City("Moscow")
val thirdCity = City("Hanoi")
firstCity.degrees = first
secondCity.degrees = second
thirdCity.degrees = third
println(first)
println(second)
println(third)
What's wrong in the setter? Why does the second doesn't set the default values?
Works as expected to me https://pl.kotl.in/otINdg8E3:
class City(val name: String) {
var degrees: Int = 0
set(value) {
field =
if (value > 57 || -92 > value) {
when (this.name) {
"Dubai" -> 30
"Moscow" -> 5
"Hanoi" -> 20
else -> 0
}
} else {
value
}
}}
fun main() {
val firstCity = City("Dubai")
val secondCity = City("Moscow")
val thirdCity = City("Hanoi")
firstCity.degrees = 100
secondCity.degrees = -100
thirdCity.degrees = 6
println(firstCity.degrees) // prints 30
println(secondCity.degrees) // prints 5
println(thirdCity.degrees) // prints 6
}

What is a good way to store static data? Like items and their stats, rewarddata or waypoints on a map for a towerdefense game

Here is how I'm currently storing/calling the rewarddata:
class Map(context: Context, screenX: Int, screenY: Int) {
var level = 0
var stage = 0
val screenWidth = screenX
val screenHeight = screenY
var xpReward = 0f
var goldReward = 0f
fun getRewardData(Level: Int = level, Stage: Int = stage): Array<Float> {
when (Level) {
0 -> {
when (Stage) {
0 -> {
goldReward = 50f
xpReward = 15f
}
1 -> {
}
2 -> {
}
}
}
}
return arrayOf(xpReward, goldReward)
}
}
Then in a different class I'm calling for the data so I can display it:
val rewards = map.getRewardData(chosenLevel, levelSelectScreen.stage)
It all just feels inefficient/amateuristic or at least like there should be a better way to do this.
You can use a Map here:
data class LevelStage(val level: Int, val stage: Int)
data class Reward(val gold: Int, val xp: Int)
val levelToReward = mapOf(
LevelStage(1, 1) to Reward(10, 10),
LevelStage(2, 1) to Reward(20, 10),
)
val reward = levelToReward[LevelStage(chosenLevel, levelSelectScreen.stage)]
You can store the data in a json file like
{
"0" : {
"0" : {
"goldReward": 50,
"xpReward": 15
},
"1" : {
"goldReward": 50,
"xpReward": 15
}
},
"1" : {
"0" : {
"goldReward": 50,
"xpReward": 15
},
"1" : {
"goldReward": 50,
"xpReward": 15
}
}
}
and whenever you need the data you can fetch from json file
I use Jackson to serialize objects such as what you're likely suggesting.
For my game, I store configurable data [item boosts] in flat files instead of in code.

Kotlin Integer.MAX_VALUE Returns Negative Number

Expected
Use Integer.MAX_VALUE in order to consistently return a large number for the purposes of comparison.
Observed
Integer.MAX_VALUE is returning a negative number.
Implement
In the sample code values are saved into a 2D table in order to find the minimum amount of coins required to make up a given amount.
Using Integer.MAX_VALUE
-2147483647 is being derived from Integer.MAX_VALUE.
fun main() {
// Steps - Iterative/bottom-up
// 1. Create a 2D table: Rows = Denominations(Denoms), Columns = Amount(Amt)
// 2. Store min # of coins in at [R][C] = Min(currentDenomMin, previousDenomMin)
// a. currentDenomMin = [R][C - coins.get(R)] + 1
// b. previousDenomMin = [R - 1][C]
// 3. Return minCount or -1 for table[coins.size - 1, Amt].
println("Min count: ${coinChange(intArrayOf(2), 3)}")
}
lateinit var table: Array<IntArray>
lateinit var mCoins: IntArray
private val maxValue = Integer.MAX_VALUE
fun coinChange(coins: IntArray, amt: Int): Int {
table = Array(coins.size, { IntArray(amt + 1) })
mCoins = coins
coins.sort()
buildMinCounts(amt)
val minCount = table[coins.size - 1][amt]
return if (minCount == maxValue) -1 else minCount
}
fun buildMinCounts(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
val currentDenomValue = mCoins.get(r)
val currentDenomMin = getDenomMin(r, c - currentDenomValue) + 1
val previousDenomMin = getDenomMin(r - 1, c)
if (c == 0) {
table[r][c] = 0
} else table[r][c] = Math.min(currentDenomMin, previousDenomMin)
}
}
}
fun getDenomMin(r: Int, c: Int): Int {
if (r < 0 || c < 0) return maxValue
else return table[r][c]
}
fun printT(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
print("${table[r][c]} ")
}
println("")
}
}
Using 999999999 as the maxValue instead
Works as expected.
fun main() {
println("Min count: ${coinChange(intArrayOf(2), 3)}")
}
lateinit var table: Array<IntArray>
lateinit var mCoins: IntArray
private val maxValue = 999999999
fun coinChange(coins: IntArray, amt: Int): Int {
table = Array(coins.size, { IntArray(amt + 1) })
mCoins = coins
coins.sort()
buildMinCounts(amt)
val minCount = table[coins.size - 1][amt]
return if (minCount == maxValue) -1 else minCount
}
fun buildMinCounts(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
val currentDenomValue = mCoins.get(r)
val currentDenomMin = getDenomMin(r, c - currentDenomValue) + 1
val previousDenomMin = getDenomMin(r - 1, c)
if (c == 0) {
table[r][c] = 0
} else table[r][c] = Math.min(currentDenomMin, previousDenomMin)
}
}
}
fun getDenomMin(r: Int, c: Int): Int {
if (r < 0 || c < 0) return maxValue
else return table[r][c]
}
fun printT(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
print("${table[r][c]} ")
}
println("")
}
}
It's because of overflow. getDenomMin(r, c - currentDenomValue) + 1 returns Integer.MAX_VALUE + 1 which causes overflow. There are two ways to avoid this:
Change maxValue to something such that it doesn't overflows and is actually is the maximum. For example, you have array of size 10^5 containing integers between 1 and 10^9. Now maximum possible sum will 10^5 * 10^9 which is 10^14 so we can set maxValue to any value greater than or equal to 10^14. In your case you can set it to something like 10^5 because you need count not sum which can be at max number of coins available.
val currentDenomMin = getDenomMin(r, c - currentDenomValue) + 1 Before adding 1 you can type it to Long so that it doesn't overflow.
val currentDenomMin = getDenomMin(r, c - currentDenomValue).toLong + 1