How to shuffle a hashmap in kotlin - kotlin

I have created a hashmap. Now I want to shuffle the objects in it. We have Collections.shuffle() to shuffle all the elements in a list. How can I do the same in hashmap?
This is my hashmap:
val tips = hashMapOf("Having a balanced diet is the key" to "Have nutritious foods like vegetables and fruits along with legumes, whole wheat, cereals etc., at regular intervals. Avoid oily and spicy food to ease your pregnancy symptoms. Plan your food intake and have it as 4-5 light meals every day."
, "Fluids will help you manage" to "Drink sufficient water and fluids to maintain the retention of water in your body. This will help you control constipation, indigestion, dryness, fatigue, bloating and gas. Avoid alcohol and caffeine drinks which may have serious effects during pregnancy."
, "Do not miss prenatal supplements" to "Doctors prescribe prenatal vitamin and mineral supplements for the normal growth and development. Do not skip these supplements as they can prevent preterm labour and many serious health concerns in the newborn."
, "Folic acid is essential" to "During pregnancy, have folic acid (supplement) or folate (natural source of folic acid) to avoid various health problems. They are rich in green leafy vegetables, oranges, avocado etc.")

This code should work:
tips.map { it.key to it.value }.shuffled().toMap()
It converts Map to List, shuffles it and then converts back to Map.

I am assuming that you want a random tip, but not the same one twice until the map is exhausted. For that, you should not alter the map at all. Use a singleton which provides you with random tips like that.
val tips = /*...*/
fun main(args: Array<String>) {
val (title, text) = TipProvider.next()
println("$title: $text")
}
object TipProvider {
var tipPool = mutableListOf<String>()
fun next(): Pair<String, String> {
if(tipPool.isEmpty()) {
// create copy of keys
tipPool = mutableListOf(*(tips.keys.shuffled().toTypedArray()))
}
val nextTipKey = tipPool.first()
tipPool.remove(nextTipKey)
return nextTipKey to tips[nextTipKey]!!
}
}

Related

Combine two LiveData<Int> into one LiveData<List<Pair<Int, Int>>>

I want to display a dot plot chart with points having calories consumed as x coordinates and calories burned as y cordinates. I retreive both of the calories in my ViewModel but i want to combine them in a single LiveData<List<Pair<Int, Int>>>. This way i can observe this LiveData in my fragment and access the list of Pairs having the x and y coordinates (calories).
This is my DAO where i have the two liveDatas of type List<Int>:
#Query("SELECT amount from calories_table WHERE strftime('%m-%d-%Y', timestamp, 'unixepoch') IN (SELECT strftime('%m-%d-%Y', timestamp, 'unixepoch') FROM running_table)")
fun getCaloriesConsumedOnRunDays(): LiveData<List<Int>>
#Query("SELECT caloriesBurned FROM running_table")
fun getCaloriesFromRuns():LiveData<List<Int>>
This is my repository:
fun getCaloriesConsumedOnRunDays() = runDao.getCaloriesConsumedOnRunDays()
fun getCaloriesFromRuns() = runDao.getCaloriesFromRuns()
Lastly i create these two variables in my ViewModel that store the two liveDatas:
private val getCaloriesConsumedOnRunDays = mainRepository.getCaloriesConsumedOnRunDays()
private val getCaloriesFromRuns = mainRepository.getCaloriesFromRuns()
First of all, this being your first question, welcome.
There are two approaches to what you're trying to do.
This is specific to what you're trying to do... I would recommend just pulling all the data out in a single SQLite query call, would be the more efficient way to go. SQLite runs at C-level speed, you'd rather let it do all the heavy lifting instead of doing glue code with Kotlin on the VM. (Also, would avoid using a sub-select, plus if you're just doing WHERE .. IN; then there's no reason to do strftime around them, since you're just trying to do straight matching).
This could be a departure of what you were thinking, but something like this:
#Query("""
SELECT calories_table.amount, running_table.caloriesBurned
FROM calories_table
INNER JOIN running_table ON calories_table.timestamp = running_table.timestamp")
"""
fun getCaloriesConsumedOnRunDays(): LiveData<List<Pair<Int, Int>>>
(if ROOM precompiler doesn't like having Pair<Int, Int> there, make a new data class, something like data class CaloriesInfo(val amount: Int, val caloriesBurned: Int) and use that as your return data type instead)
This way you just a need a single LiveData.
Sometimes you can have legitimate usecase that you need to merge two or more LiveData together, in which case you should use MediatorLiveData.
Something like:
val mediator: MediatorLiveData<Pair<Int, Int>> = MediatorLiveData()
val liveData1 = repo.getLiveData()
val liveData2 = repo.getAnotherLiveData()
mediator.addSource(liveData1) { mediator.postValue(it to liveData2.value) }
mediator.addSource(liveData2) { mediator.postValue(liveData1.value to it) }
There are sometimes good reasons to do this, but I don't recommend this for what you're saying you're trying to do, as you need to do additional things to get the data in the right format that would be useful for you to plot. LiveData runs asynchronously, so it doesn't make sense for x and y to come from different LiveData when you're trying to plot things. Your best bet is still do a nicer SQLite query and do it in a single query.

How to group a list by a value?

I have a list and I want to make an object of all the values that contain a certain id.
val list = listOf(A(id = 1), A(1), A(2), A(3), A(2))
From that list I want to make a new list of type Container
data class Container(
val id: Long // The id passed into A.
val elementList: List<A> // The elements that contain the ID.
)
How can I do this in an efficient way without going O(n^2)?
You can use groupBy + map.
The implementation of groupBy is O(n) and the implementation of map is O(n) so the total runtime is O(2n) which is O(n).
list.groupBy { it.id }.map { (id, elementList) -> Container(id, elementList) }
Since this is so short and readable, I'd avoid to make further optimizations if not strictly needed but, if you'd need some further optimizations, you can reduce also the space cost avoiding to allocate multiple lists for example.

How to convert two lists into a list of pairs based on some predicate

I have a data class that describes a chef by their name and their skill level and two lists of chefs with various skill levels.
data class Chef(val name: String, val level: Int)
val listOfChefsOne = listOf(
Chef("Remy", 9),
Chef("Linguini", 7))
val listOfChefsTwo = listOf(
Chef("Mark", 6),
Chef("Maria", 8))
I'm to write a function that takes these two lists and creates a list of pairs
so that the two chefs in a pair skill level's add up to 15. The challenge is to do this using only built in list functions and not for/while loops.
println(pairChefs(listOfChefsOne, listOfChefsTwo))
######################################
[(Chef(name=Remy, level=9), Chef(name=Mark, level=6)),
(Chef(name=Linguini, level=7), Chef(name=Maria, level=8))]
As I mentioned previously I'm not to use any for or while loops in my implementation for the function. I've tried using the forEach function to create a list containing all possible pairs between two lists, but from there I've gotten lost as to how I can filter out only the correct pairs.
I think the clue is in the question here!
I've tried using the forEach function to create a list containing all possible pairs between two lists, but from there I've gotten lost as to how I can filter out only the correct pairs.
There's a filter function that looks perfect for this…
To keep things clear, I'll split out a function for generating all possible pairs.  (This is my own, but bears a reassuring resemblance to part of this answer!  In any case, you said you'd already solved this bit.)
fun <A, B> Iterable<A>.product(other: Iterable<B>)
= flatMap{ a -> other.map{ b -> a to b }}
The result can then be:
val result = listOfChefsOne.product(listOfChefsTwo)
.filter{ (chef1, chef2) -> chef1.level + chef2.level == 15 }
Note that although this is probably the simplest and most readable way, it's not the most efficient for large lists.  (It takes time and memory proportional to the product of the sizes of the two lists.)  You could improve large-scale performance by using streams (which would take the same time but constant memory). But for this particular case, it might be even better to group one of the lists by level, then for each element of the other list, you could directly look up a Chef with 15 - its level.  (That would time proportional to the sum of the sizes of the two lists, and space proportional to the size of the first list.)
Here is the pretty simple naive solution:
val result = listOfChefsOne.flatMap { chef1 ->
listOfChefsTwo.mapNotNull { chef2 ->
if (chef1.level + chef2.level == 15) {
chef1 to chef2
} else {
null
}
}
}
println(result) // prints [(Chef(name=Remy, level=9), Chef(name=Mark, level=6)), (Chef(name=Linguini, level=7), Chef(name=Maria, level=8))]

Kotlin: Why is Sequence more performant in this example?

Currently, I am looking into Kotlin and have a question about Sequences vs. Collections.
I read a blog post about this topic and there you can find this code snippets:
List implementation:
val list = generateSequence(1) { it + 1 }
.take(50_000_000)
.toList()
measure {
list
.filter { it % 3 == 0 }
.average()
}
// 8644 ms
Sequence implementation:
val sequence = generateSequence(1) { it + 1 }
.take(50_000_000)
measure {
sequence
.filter { it % 3 == 0 }
.average()
}
// 822 ms
The point here is that the Sequence implementation is about 10x faster.
However, I do not really understand WHY that is. I know that with a Sequence, you do "lazy evaluation", but I cannot find any reason why that helps reducing the processing in this example.
However, here I know why a Sequence is generally faster:
val result = sequenceOf("a", "b", "c")
.map {
println("map: $it")
it.toUpperCase()
}
.any {
println("any: $it")
it.startsWith("B")
}
Because with a Sequence you process the data "vertically", when the first element starts with "B", you don't have to map for the rest of the elements. It makes sense here.
So, why is it also faster in the first example?
Let's look at what those two implementations are actually doing:
The List implementation first creates a List in memory with 50 million elements.  This will take a bare minimum of 200MB, since an integer takes 4 bytes.
(In fact, it's probably far more than that.  As Alexey Romanov pointed out, since it's a generic List implementation and not an IntList, it won't be storing the integers directly, but will be ‘boxing’ them — storing references to Int objects.  On the JVM, each reference could be 8 or 16 bytes, and each Int could take 16, giving 1–2GB.  Also, depending how the List gets created, it might start with a small array and keep creating larger and larger ones as the list grows, copying all the values across each time, using more memory still.)
Then it has to read all the values back from the list, filter them, and create another list in memory.
Finally, it has to read all those values back in again, to calculate the average.
The Sequence implementation, on the other hand, doesn't have to store anything!  It simply generates the values in order, and as it does each one it checks whether it's divisible by 3 and if so includes it in the average.
(That's pretty much how you'd do it if you were implementing it ‘by hand’.)
You can see that in addition to the divisibility checking and average calculation, the List implementation is doing a massive amount of memory access, which will take a lot of time.  That's the main reason it's far slower than the Sequence version, which doesn't!
Seeing this, you might ask why we don't use Sequences everywhere…  But this is a fairly extreme example.  Setting up and then iterating the Sequence has some overhead of its own, and for smallish lists that can outweigh the memory overhead.  So Sequences only have a clear advantage in cases when the lists are very large, are processed strictly in order, there are several intermediate steps, and/or many items are filtered out along the way (especially if the Sequence is infinite!).
In my experience, those conditions don't occur very often.  But this question shows how important it is to recognise them when they do!
Leveraging lazy-evaluation allows avoiding the creation of intermediate objects that are irrelevant from the point of the end goal.
Also, the benchmarking method used in the mentioned article is not super accurate. Try to repeat the experiment with JMH.
Initial code produces a list containing 50_000_000 objects:
val list = generateSequence(1) { it + 1 }
.take(50_000_000)
.toList()
then iterates through it and creates another list containing a subset of its elements:
.filter { it % 3 == 0 }
... and then proceeds with calculating the average:
.average()
Using sequences allows you to avoid doing all those intermediate steps. The below code doesn't produce 50_000_000 elements, it's just a representation of that 1...50_000_000 sequence:
val sequence = generateSequence(1) { it + 1 }
.take(50_000_000)
adding a filtering to it doesn't trigger the calculation itself as well but derives a new sequence from the existing one (3, 6, 9...):
.filter { it % 3 == 0 }
and eventually, a terminal operation is called that triggers the evaluation of the sequence and the actual calculation:
.average()
Some relevant reading:
Kotlin: Beware of Java Stream API Habits
Kotlin Collections API Performance Antipatterns

Designing a food ingredient class in OOP

I want to suggest recipes to my users, so I'm fetching recipes from a JSON source (including their ingredients).
At the moment, ingredients can be fetched from three ways:
3 tomatoes (no particular unit)
125ml of milk (volume unit, either metric or imperial)
500g of pasta (mass unit, either metric or imperial)
Requirements
I want to use a DDD approach, so a layered architecture.
I need to be able to display the ingredient as-is, like suggested in my bullet list above. The user can choose between a metric or imperial view.
3 tomatoes
125ml of milk or 1/2 cup of milk
55g of pasta or 2 ounces of pasta
My challenge
I'm not sure how to design the class in order to respect encapsulation and to ensure an easy-to-maintain design.
My first idea was to represent units with a Unit class, so my Ingredient class would hold a quantity and a unit. But in some cases, the ingredient is unitless. With this idea in mind, my IngredientPresenter would look like this:
public String present(Ingredient ingredient) {
if ( ingredient.isUnitless() )
return ingredient.getQuantity() + " " + ingredient.getName();
else
return ingredient.getUnit() + " " + ingredient.getName();
}
I'm not convinced with this approach since I could have many different types of units, and so my IngredientPresenter would grow rapidly (and violating OCP).
Then, I thought I could go with polymorphism. While it seems a good approach, I don't know what to expose in my interface since my implementations would be completely different. I would need to expose my methods in implementations, so loosing all the benefits of polymorphism. My IngredientPresenter would look like below:
public String present(Ingredient ingredient) {
if ( ingredient instanceof UnitlessIngredient ) {
UnitlessIngredient actualIngredient = (UnitlessIngredient) ingredient;
return actualIngredient.getQuantity() + " " + actualIngredient.getName();
} else {
WithUnitIngredient actualIngredient = (WithUnitIngredient) ingredient;
return actualIngredient.getUnit() + " " + actualIngredient.getName();
}
}
Actually, I think my problem is that I don't know how to represent units properly, so I'm looking your help.
Thank you for your time!
Edit
I will not only present my ingredient. In my domain layer, I need to calculate the ingredient's nutriment facts. So, depending on its quantity (or volume, or mass), the calculation is done differently. One simply multiply the nutriment facts by the quantity while the other must perform a pro-rata. That's a perfect case of polymorphism.
Definitely go with polymorphism.
The way this is normally done is that present() stops being a standalone function in a vacuum, and it becomes a method of the Ingredient instead.
So, you essentially call the Ingredient to render itself into a string. Possibly with some parameter indicating metric vs. imperial, which the ingredient may have some use for, or it may ignore if unitless. Simple, elegant, tried, it works.