Skip to content

Instantly share code, notes, and snippets.

@NicolaM94
Last active June 15, 2024 22:10
Show Gist options
  • Save NicolaM94/d65b859355560d03823ca95dbe59df71 to your computer and use it in GitHub Desktop.
Save NicolaM94/d65b859355560d03823ca95dbe59df71 to your computer and use it in GitHub Desktop.
Kotlin implementation for the LFU (Least Frequently Used) cache algorithm
package main
// Object stored in the cache, could be anything
class Object (val key: String, val value: Int)
class LeastFrequentlyUsed (private val cacheLimit :Int) {
// Holds objects
private val cache = mutableListOf<Object>()
// Keeps track of hashes -> index, used in get(key) => hash(key) => index
private val indexLinks = mutableMapOf<Int,Int>()
// Keeps track of calls
private val calledObjects = mutableMapOf<Int, Int>()
// Keeps track of the last inserted index
private var lastInserted :Int = 0
// Collectors and printer for the LFU cache state
private fun collectCache() :MutableList<Pair<String,Int>> {
val collector = mutableListOf<Pair<String,Int>>()
cache.forEach {
collector.add(Pair(it.key, it.value))
}
return collector
}
private fun collectCounters () :MutableList<Pair<String,Int>> {
val collector = mutableListOf<Pair<String,Int>>()
cache.forEach {
collector.add(Pair(
it.key,
calledObjects[it.key.hashCode()]!!
))
}
return collector
}
private fun collectIndexLinks () :MutableList<Pair<String,Int>> {
val collector = mutableListOf<Pair<String,Int>>()
cache.forEach {
collector.add(Pair(
it.key,
indexLinks[it.key.hashCode()]!!
))
}
return collector
}
fun printLfu() {
println("Cache: ${collectCache()}")
println("Counters: ${collectCounters()}")
println("IndexLinks: ${collectIndexLinks()}")
println()
}
// LFU setter
fun set(key :String, value: Int) {
val hashKey = key.hashCode()
// If we reached the cache limit we need to take away the less used item in the cache
if (lastInserted == cacheLimit) {
// Lower lastInserted of 1 just to bring it back to max later
lastInserted--
// Brings up least used item, stored in the last index of the cache
val lessUsedItem = cache.last()
// Removes the least used item from cache
cache.removeLast()
// Clears indexLinks from the element removed from cache
indexLinks.remove(lessUsedItem.key.hashCode())
// Clears calledObjects from the element removed from cache
calledObjects.remove(lessUsedItem.key.hashCode())
}
// Adds the new element to cache
cache.add(Object(key,value))
// Adds the new element to indexLinks
indexLinks[hashKey] = lastInserted
// Adds the new element to calledObjects
calledObjects[hashKey] = 0
// Turns back lastInserted to max = cache limit
lastInserted++
}
// LFU getter
fun get (key :String) :Object? {
val hashKey = key.hashCode()
// Verify if the key is present in the LFU
indexLinks[hashKey] ?: return null
// Updates the calledObjects counter
calledObjects[hashKey] = calledObjects[hashKey]!!.plus(1)
// Gets the current element position in the cache
val currentItemIndex = indexLinks[hashKey]!!
if (currentItemIndex > 0 ) {
// Gets the previous element position in the cache, which is the current -1
val previousItemIndex = currentItemIndex - 1
// Gets the key of the previous item to find it in calledObjects and see its number of calls
val previousItemKey = cache[previousItemIndex].key.hashCode()
// Checks which is the most called: the current or the previous.
// If is the current, swap the two
if (calledObjects[hashKey]!! > calledObjects[previousItemKey]!!) {
// Adjusts the position in the cache
val temp = cache[previousItemIndex]
cache[previousItemIndex] = cache[currentItemIndex]
cache[currentItemIndex] = temp
// Adjusts their indices in the indexLists map
indexLinks[hashKey] = indexLinks[hashKey]!! - 1
indexLinks[previousItemKey] = indexLinks[previousItemKey]!! + 1
}
}
return cache[indexLinks[hashKey]!!]
}
}
fun main () {
val lfu = LeastFrequentlyUsed(3)
lfu.set("Alice", 10)
lfu.set("Bob", 20)
lfu.set("Charlie",30)
lfu.printLfu()
lfu.get("Charlie")
lfu.get("Charlie")
lfu.set("Dean", 50)
lfu.get("Dean")
lfu.printLfu()
lfu.get("gianni")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment