Having an issue with mutablemap in Kotlin - 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)

Related

How to use an item in a Map<Map<x, y> z>?

I need to make a built-in counter of the number of things through the Map in the Map.
initialization:
var Items = mapOf<Map<String, Item>, Int>()
Example of interaction
for(i in item)
if (this.UnitInventory.Items.containsKey(Pair(i.Name, i) as Map<String, Item>))
this.UnitInventory.Items[Pair(i.Name, i)]++
else
this.UnitInventory.Items += mapOf(Pair(Pair(i.Name, i) as Map<String, Item>, 1))
How to properly write part this.UnitInventory.Items[Pair(i.Name, i)]++?
Like Tenfour04 says in the comments, this is kinda brittle - but so long as you're using immutable Maps as keys it's probably ok? Anyway, if that's what you want, you can do this:
// this -outer- map needs to be mutable (since you'll be adding new counts)
val items = mutableMapOf<Map<String, Int>, Int>()
// make some map keys to count
val someMap = mapOf("One" to 1)
val someOtherMap = mapOf("Two" to 2, "Three" to 3)
val stuff = listOf(someMap, someOtherMap, someMap)
// add them to the counts
stuff.forEach { item ->
// update the current count, defaulting to zero if it doesn't exist yet
items[item] = items.getOrDefault(item, 0) + 1
}
println(items)
>> {{One=1}=2, {Two=2, Three=3}=1}

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.

Difference Between Two List Elements in 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))
}

Continue zip(), if one source is completed

I have some troubles with .zip() operator.
Let me simplify my problem on a small example.
Flux<Integer> flux1 = Flux.just(9, 8, 3, -2);
Flux<Integer> flux2 = Flux.just(7);
Flux<Integer> flux3 = Flux.just(6, 5, 4, -4);
List<Flux<Integer>> list1 = Arrays.asList(flux1, flux2, flux3);
TreeSet<Integer> set = new TreeSet<>(Comparator.reverseOrder());
Set<Integer> list = Flux.zip(list1, objects -> {
boolean setChanged = false;
for (Object o : objects) {
Integer i = (Integer) o;
if (set.size() < 5 || i > set.last()) {
setChanged = true;
set.add(i);
if (set.size() > 5) {
set.pollLast();
}
}
}
return setChanged;
}).takeWhile(val -> val)
.then(Mono.just(set))
.block();
System.out.println(list);
Here I have 3 different sources(they are sorted descending by default, and the number of them could be much bigger), and I want to get from them a collection of 5 elements sorted descending. Unfortunately, I can't just use concat() or merge() operators, because sources in a real life can be really big, but I need only small amount of elements.
I am expecting [9, 8, 7, 6, 5] here, but one of the sources is completed after first iteration of zipping.
Could you please suggest how I can get around with this problem?
You can try the reduce operation
#Test
void test() {
Flux<Integer> flux1 = Flux.just(9, 8, 3, -2);
Flux<Integer> flux2 = Flux.just(7, 0, -2, 4,3,2,2,1);
Flux<Integer> flux3 = Flux.just(6, 5, 4, -4);
var k = 5;
List<Flux<Integer>> publishers = List.of(flux1, flux2, flux3);
var flux = Flux.merge(publishers)
.log()
.limitRate(2)
.buffer(2)
.reduce((l1, l2) -> {
System.out.println(l1);
System.out.println(l2);
return Stream.concat(
l1.stream(),
l2.stream()
).sorted(Comparator.reverseOrder())
.limit(k)
.collect(Collectors.toList());
})
.log();
StepVerifier.create(flux)
.expectNext(List.of(9,8,7,6,5))
.expectComplete()
.verify();
}
You can fetch data in chunks and compare them to find the top K elements.
In a sequential case it will fetch a new batch, compare it to the current top k result and return a new topk like in the example above (PriorityQueue may work better for sorting if k is big).
If you're using parallel schedulers and batches are fetched in parallel, then it can compare them with each other independently that should be a bit faster.
Also you have full control over the fetched data via rateLimit, buffer, delayElements, etc

How to map a list by chunks in kotlin

I often end up with data sources like (pseudo code below, not any specific syntax, it is just to illustrate):
list = {
"XLabel",
"XDescription",
"YLabel",
"YDescription",
"ZLabel",
"ZDescription"
}
desired output is:
list = {
MyClass("XLabel", "XDescription"),
MyClass("YLabel", "YDescription"),
MyClass("ZLabel", "ZDescription")
}
Is there anything more clean than to do a fold(), and fold it into a new list? I've also rejected doing something weird like list.partition().zip()
I basically want a more powerfull map that would work like mapChunks( it1, it2 -> MyClass(it1, it2)) where the chunking is part of the function so it gets easy and nice. (My example has the list in chunks of two, but 3 is also a prevalent use case.)
Does this function exist? Or what is the most idiomatic way to do this?
You can use the chunked function, and then map over the result. The syntax gets very close to what you wanted if you destructure the lambda-argument:
list.chunked(2)
.map { (it1, it2) -> MyClass(it1, it2) }
// Or use _it_ directly: .map { MyClass(it[0], it[1]) }
I think the windowed method should do what you want.
lst.windowed(size = 2, step = 2, partialWindows = false) { innerList -> MyClass(innerList[0], innerList[1]) }
You can also use chunked but it calls windowed under the hood. But with chunked you can get lists that have fewer elements than you were expecting
EDIT to answer #android developer's question about getting the indexes of the list
val lst = listOf(7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
val windowedList = lst.mapIndexed { index, it -> index to it }
.windowed(size = 2, step = 2, partialWindows = false) {
it[0].first
}
println(windowedList)
Would output
[0, 2, 4, 6, 8]
To add to the existing answers, you can use chunked function with the transform lambda passed as its second argument:
list.chunked(2) { (label, description) -> MyClass(label, description) }
This way is more efficient because the temporary list of two elements is reused across all chunks.
You can create an extension function, for example mapChunks, and reuse it:
fun List<String>.mapChunks(): List<MyClass> {
return chunked(2).map { MyClass(it[0], it[1]) }
}
val list1 = listOf(
"XLabel",
"XDescription",
"YLabel",
"YDescription",
"ZLabel",
"ZDescription"
)
val result1 = list1.mapChunks()
val list2 = listOf(
"XLabel1",
"XDescription1",
"YLabel1",
"YDescription1",
"ZLabel1",
"ZDescription1"
)
val result2 = list2.mapChunks()
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/chunked.html
Chunked returns a sub list of the size you specify
This is the API call you want
considering your list is in pairs of 2 you can do this
list.chunked(2) //List<List<String>>
.map{MyClass(it[0], it[1]} //list<MyClass>