Difference Between Two List Elements in Kotlin - kotlin

I have a data class as below in Kotlin.
data class ProductData(
val code: String,
var value: Double)
There are two list for the above data class as
lstToday: List<ProductData> contains such as
("P1", 110)
("P2", 109)
("P3", 102)
("P4", 110)
..... 100+ records
and
lstYesterday: List<ProductData> contains such as
("P1", 112)
("P2", 109)
("P3", 110)
("P4", 90)
..... 100+ records
Both has the identical and exact number of records.
The output I am looking for is as below.
Output 1: Difference between yesterday and today
lstDifference: List<ProductData> contains such as
("P1", -2)
("P2", 0)
("P3", 8)
("P4", -20)
..... 100+ records
Output 2: Today Price and Difference between yesterday and today
using the data class below.
data class ProductDisplayData(
val code: String,
var value: Double,
var diff: Double
)
With list as below
lstDifference: List<ProductData> contains such as
("P1", 112, -2)
("P2", 109, 0)
("P3", 110, 8)
("P4", 90, -20)
..... 100+ records
Can this be achieved using any functions Kotlin, or is it we have loop each element and get the result.
Thanks

I would say this is not the most efficient solution. We're talking 0n ish. This could definitely be optimized. To note, this is fault tolerant of the code itself not being included in both days, and assumes 0 for a non-existent value between days.
Trying to guarantee that both data sets will always be the same, is going to be more maintenance than writing code that will tolerate that mistake.
data class ProductData(
val code: String,
var value: Double
)
val dayOne = listOf(
ProductData("P1", 110.0),
ProductData("P2", 109.0),
ProductData("P3", 102.0),
ProductData("P4", 110.0),
ProductData("P5", 105.0),
ProductData("P6", 104.0),
ProductData("P8", 32.0) // Not in set 2
)
val dayTwo = listOf(
ProductData("P1", 110.0),
ProductData("P2", 109.0),
ProductData("P3", 102.0),
ProductData("P4", 90.0),
ProductData("P5", 49.0),
ProductData("P6", 123.0),
ProductData("P7", 239.0) // Not in set 1
)
fun periodDataDifference(dayOne: List<ProductData>, dayTwo: List<ProductData>): List<ProductData> {
val mapOne = dayOne.associate { it.code to it.value }
val mapTwo = dayTwo.associate { it.code to it.value }
val keys = mapOne.keys + mapTwo.keys
return keys.map { key ->
val first = mapOne[key] ?: 0.0
val second = mapTwo[key] ?: 0.0
ProductData(key, second - first)
}
}
val out = periodDataDifference(dayOne, dayTwo)
println(out)
/*
[ProductData(code=P1, value=0.0),
ProductData(code=P2, value=0.0),
ProductData(code=P3, value=0.0),
ProductData(code=P4, value=-20.0),
ProductData(code=P5, value=-56.0),
ProductData(code=P6, value=19.0),
ProductData(code=P8, value=-32.0), // Set 1 only
ProductData(code=P7, value=239.0)] // Set 2 only
*/

If today and yesterday lists are gonna be same size this is the quickest solution I have
val lstYesterday: List<ProductData> = listOf(
ProductData("P1", 112.0),
ProductData("P2", 109.0),
ProductData("P3", 110.0)
)
val lstToday: List<ProductData> = listOf(
ProductData("P1", 110.0),
ProductData("P2", 109.0),
ProductData("P3", 102.0)
)
val lstDifference: MutableList<ProductData> = mutableListOf()
for ((index,j) in lstToday.withIndex()){
val code = lstToday[index].code
val value = lstToday[index].value-lstYesterday[index].value
lstDifference.add(ProductData(code,value))
}

Related

How to use Lucene's DistinctValuesCollector?

My objective is to collect distinct values of select fields to provided them as filter options for the frontend. DistinctValuesCollector seems to be the tool for this, however since I haven't found code sample and documentation except for the Javadocs I can't currently correctly construct this collector. Can anyone provide an example?
This is my attempt which doesn't deliver the desired distinct values of the field PROJEKTSTATUS.name.
val groupSelector = TermGroupSelector(PROJEKTSTATUS.name)
val searchGroup = SearchGroup<BytesRef>()
val valueSelector = TermGroupSelector(PROJEKTSTATUS.name)
val groups = mutableListOf(searchGroup)
val distinctValuesCollector = DistinctValuesCollector(groupSelector, groups, valueSelector)
That field is indexed as follows:
document.add(TextField(PROJEKTSTATUS.name, aggregat.projektstatus, YES))
document.add(SortedDocValuesField(PROJEKTSTATUS.name, BytesRef(aggregat.projektstatus)))
Thanks to #andrewJames's hint to a test class I could figure it out:
fun IndexSearcher.collectFilterOptions(query: Query, field: String, topNGroups: Int = 128, mapper: Function<String?, String?> = Function { it }): Set<String?> {
val firstPassGroupingCollector = FirstPassGroupingCollector(TermGroupSelector(field), Sort(), topNGroups)
search(query, firstPassGroupingCollector)
val topGroups = firstPassGroupingCollector.getTopGroups(0)
val groupSelector = firstPassGroupingCollector.groupSelector
val distinctValuesCollector = DistinctValuesCollector(groupSelector, topGroups, groupSelector)
search(query, distinctValuesCollector)
return distinctValuesCollector.groups.map { mapper.apply(it.groupValue.utf8ToString()) }.toSet()
}

Kotlin Unparseable and - NullPointerException error

What I expect: the 'for loop' brings the number of columns that will be displayed in the table, the start date, and the end date are taken by an object. the transaction date is taken by a different object. The start date variable gets the exception and the transaction date gets the value without a problem.
Code:
if(date >0){//no of dates for the selected week
for (i in 0 until date) {
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
val tv_Date = TextView(this)
val transDate = SortedDateHashMap[i].transactionDate
val start = SortedExpenseDateHashMap[i]!!.weekStart
val end = SortedExpenseDateHashMap[i]!!.weekEnd
val startDate = dateFormat.parse(start)
val endDate = dateFormat.parse(end)
var transactionDat = dateFormat.parse(transDate)
if(transactionDat.before(endDate) && transactionDat.after(startDate)){
setColor(tv_Date)
tv_Date.setPadding(10, 15, 10, 10)
tv_Date.gravity = Gravity.CENTER
tv_Date.layoutParams = params3
tv_Date.text = SortedDateHashMap[i].transactionDate
}
}
}
Used null safe and wrote the code in the try..catch exception. Worked

Kotlin, is it possible to access the pair of a map?

Is it possible to access the whole Pair of a map, not only the key or a value?
Let's say we have a map
map = mapOf(Pair("Example1", 1), Pair("Example2", 2), Pair("Example3",
3))
I would like to access the second pair and put it into a variable, something like I would do with a list:
val ex2 = map[1] #this would result with {"Example2", 2}
And then i would be able to access the pair's key/value like:
ex2.key / ex2.value
More specifically, I would like to use this in my function to return a specific pair of the map.
Not sure if this would help
val mapString = mutableMapOf(1 to "Person", 2 to "Animal")
val (id, creature) = 1 to mapString.getValue(1)
Log.e("MapPair", "$id, $creature")
prints
1, Person
or if you're iterating through the entire map
mapString.forEach {
val (id, creature) = it.key to it.value
Log.e("MapPair", "$id : $creature")
}
prints
1 : Person
2 : Animal
or using Pair
val key = 1
val pair = Pair(key, mapString.getValue(key))
Log.e("MapPair", "$pair")
prints
(1, Person)
or if you're iterating through the entire map using Pair
mapString.forEach {
val pair = Pair(it.key, it.value)
Log.e("MapPair", "$pair")
}
prints
(1, Person)
(2, Animal)
Update: For iterating through the map you can also go with Destructuring Declarations
val mapString = mutableMapOf(1 to "Person", 2 to "Animal")
for ((key, value) in mapString) {
Log.e("MapComponents", "$key, $value")
}
From your comment, it seems like you want to fetch the key corresponding to a given value.
val map = mapOf("Chicken" to 20, "Egg" to 10, "Bread" to 5)
val valueToFind = 20
val key = map.toList().find { it.second == valueToFind }?.first
println(key)
Output:
Chicken
If the value doesn't exist, it will give null.

Having an issue with mutablemap in Kotlin

I'm working on an algorithm type challenge, and i am debugging via print statements and i can't seem to figure out why the the values for keys are not what i am expecting
var mapNums = mutableMapOf<Int, Int>()
//imaginary array
//var nums = [34,28,11,21,3,34,8,7,34,7,31,7,3,28,18]
var count = 0
for (n in nums) {
if (mapNums.containsKey(n)) {
count ++
mapNums[n] = count
} else if (!mapNums.containsKey(n)) {
count = 1
mapNums[n] = count
}
}
println(mapNums)
//prints {34=2, 28=4, 11=1, 21=1, 3=3, 8=1, 7=2, 31=1, 18=1}
as you can see the key and values aren't what theyre supposed to be and i am not sure why.
You can use the following code to generate the desired map:
val nums = intArrayOf(34, 28, 11, 21, 3, 34, 8, 7, 34, 7, 31, 7, 3, 28, 18).toList()
println(nums.groupingBy { it }.eachCount())
try it yourself
Here groupingBy creates a Grouping source using the same element as the key selector. Then eachCount groups elements from the Grouping source by key and counts elements in each group.
You can also refer the documentation for more info about groupingBy and eachCount.
It's because you reuse the same count variable outside of the loop so it keeps incrementing from different keys.
Instead you should get the current count from the map, then put it back one higher:
val nums = intArrayOf(34,28,11,21,3,34,8,7,34,7,31,7,3,28,18)
val mapNums = mutableMapOf<Int, Int>()
for (n in nums) {
val count = mapNums[n] ?: 0
mapNums[n] = count + 1
}
println(mapNums) // {34=3, 28=2, 11=1, 21=1, 3=2, 8=1, 7=3, 31=1, 18=1}
Firstly check n number is contain this map as key, if found then increment 1 its value using plus method. If not found any value from the map, it will null and check if null and set 1.
var mapNums = mutableMapOf<Int, Int>()
//imaginary array
var nums = arrayOf(34,28,11,21,3,34,8,7,34,7,31,7,3,28,18)
for (n in nums) {
mapNums[n] = mapNums[n]?.plus(1) ?: 1
}
println(mapNums)

Kotlin grouping, mapping and so on

I know that a lot of this topics exists but I don't understand this topic at all. And an exact explanation of what is happening for a beginner is needed.
I have a list of persons:
val person1 = Person("A", 8, 24,"darts")
val person2 = Person("A", 8, 24,"football")
val person3 = Person("A", 2, 24,"basketball")
val person4 = Person("B", 8, 24,"skiing")
val person5 = Person("B", 1, 24,"snowboard")
where
data class Person (val street: String, val number: Int, val age: Int, val hobby: String){
override fun toString(): String {
return "$street $number $age $hobby"
}
}
And now to sum up. If I use a groupBy the result will be Map with key, and values Am I right?
Where keys are the atrributes on which I am grouping by like:
var grouping = list.groupBy { it.street }
result is:
{A=[A 8 24 darts, A 8 24 football, A 2 24 basketball], B=[B 8 24 skiing, B 1 24 snowboard]}
And now I would like to group by multiple fields like street and number. How to do this?
And moreover I would like to specify a LIST (I have to do some kind of projection from this map?) of hobbies which people have under adresses and numbers. For example under adress A number 8 i have a list of (darts,football).
#Edit
Do I have somehow to divide this list as 2nd object class?
Yes, groupBy returns a map where the keys are whatever was returned by the lambda and values are lists of items from the original list.
To group by a pair of things, you need to be able to have a key that represents all those things and be unique. The probably means another data class, or maybe you could concatenate the as a String.
data class Address(val street: String, val number: Int)
val grouping = list.groupBy { Address(it.street, it.number) }
And to make the values of the map simply the hobby, you can use mapkeys:
val addressesToHobbies = grouping.mapKeys { it.map(Person::hobby) }