Kounter
![codecov](https://camo.githubusercontent.com/c826780e2977df654bad4f09be06eb3d55315c5789b5285187341517aaf1cae3/68747470733a2f2f636f6465636f762e696f2f67682f706772657a652f6b6f756e7465722f6272616e63682f6d61737465722f67726170682f62616467652e737667)
Choose the easy-to-use Counter or the fully flexible MapWithDefault.
Installation ![central](https://camo.githubusercontent.com/69db840691eade7ca4dd3d93dae468ba9a5848ef984ab6a33a9a412093acef44/68747470733a2f2f6d6176656e2d6261646765732e6865726f6b756170702e636f6d2f6d6176656e2d63656e7472616c2f636f6d2e6769746875622e706772657a652f6b6f756e7465722f62616467652e7376673f7374796c653d2537427374796c65253744)
dependencies {
// Check the ๐ maven central badge ๐ for the latest $version
implementation("com.github.pgreze:kounter:$version")
}
repositories {
jcenter()
}
Usage ![](https://camo.githubusercontent.com/a43d13a1e0b900ca21bda51afb3954ae95f394af936a37f268bceaccb1d21a42/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f6b6b612d726561642d626c7565)
Counter / MutableCounter
A specialization of the Map class allowing to count objects.
This is similar to Guava Multiset or Python Counter, inspired by older references like Smalltalk Bag class.
Usage:
val lints = mutableCounterOf("warnings" to 20)
lints["warnings"] += 3
lints["errors"] += 1
println(lints) // {warnings=23, errors=1}
Helpers:
counterOf("aabbbcc") // {a=2, b=3, c=2}
counterOf(arrayOf('a', 'b', 'b', 'c')) // {a=1, b=2, c=1}
counterOf(listOf('a', 'a', 'b', 'c')) // {a=2, b=1, c=1}
counterOf(setOf('a', 'b', 'c')) // {a=1, b=1, c=1}
To perform mathematical operations on counters, use following methods:
val c1 = counterOf("ab")
val c2 = counterOf("ccd")
c1.plusAll(c2) // {a=2, b=3, c=2}
val chars = mutableCounterOf("ab")
chars.addAll(counterOf("ccd")) // {a=2, b=3, c=2}
MapWithDefault / MutableMapWithDefault
Counter / MutableCounter are internally using these classes.
There are also an alternative of withDefault which is a memory efficient way to specify a default value for a Map but sadly, not reflecting this change in its signature.
It's forcing users to use an unnatural getValue extension method, which is not the most intuitive way of using a Map.
Proposed alternative is slightly changing the original Map interface:
interface MapWithDefault<K, V> : Map<K, V> {
override fun get(key: K): V
}
Allowing to unlock a better syntax:
val money = mutableMapOf("Alice" to 5)
.setDefault { 0 }
money["Alice"] += 10
money["Bob"] += 3
println(money) // {Alice=15, Bob=3}
Which is shining when used with Set/List/Map:
val sets = mutableMultiSetWithDefaultOf<String, String>()
// Alias for mutableMapOf<String, Set<String>>().setDefault { setOf() }
sets += "Alice" to setOf("f1.txt")
sets["Bob"] += setOf("f2.md")
println(sets) // {"A0"= setOf("f1.txt"), "A1"= setOf("f2.md")}
Following helpers are available for common native collections:
+ setDefault | Mutable + setDefault | |
---|---|---|
List | multiListWithDefaultOf | mutableMultiListWithDefaultOf |
Set | multiSetWithDefaultOf | mutableMultiSetWithDefaultOf |
Map | multiMapWithDefaultOf | mutableMultiMapWithDefaultOf |
Alternative: Guava collection package including Multimap implemented by ListMultimap or SetMultimap.