{"id":24143641,"url":"https://github.com/pgreze/kounter","last_synced_at":"2025-07-20T01:31:39.695Z","repository":{"id":57727905,"uuid":"231913515","full_name":"pgreze/kounter","owner":"pgreze","description":"📚 Counting easily with Kotlin, and more.","archived":false,"fork":false,"pushed_at":"2022-08-10T12:46:51.000Z","size":123,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-01T14:19:09.051Z","etag":null,"topics":["counter","default","kotlin","map"],"latest_commit_sha":null,"homepage":"https://kounter.netlify.app","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pgreze.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-05T12:25:29.000Z","updated_at":"2023-12-06T14:11:35.000Z","dependencies_parsed_at":"2022-08-30T08:32:01.711Z","dependency_job_id":null,"html_url":"https://github.com/pgreze/kounter","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/pgreze/kounter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2Fkounter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2Fkounter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2Fkounter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2Fkounter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pgreze","download_url":"https://codeload.github.com/pgreze/kounter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2Fkounter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266053824,"owners_count":23869496,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["counter","default","kotlin","map"],"created_at":"2025-01-12T05:28:11.699Z","updated_at":"2025-07-20T01:31:39.675Z","avatar_url":"https://github.com/pgreze.png","language":"Kotlin","readme":"# Kounter [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ![Build](https://github.com/pgreze/kounter/workflows/Build/badge.svg?branch=master) ![codecov](https://codecov.io/gh/pgreze/kounter/branch/master/graph/badge.svg)\nChoose the easy-to-use **Counter** or the fully flexible **MapWithDefault**.\n\n## Installation  [![central](https://maven-badges.herokuapp.com/maven-central/com.github.pgreze/kounter/badge.svg?style={style})](https://search.maven.org/artifact/com.github.pgreze/kounter)\n\n```kotlin\ndependencies {\n    // Check the 🔝 maven central badge 🔝 for the latest $version\n    implementation(\"com.github.pgreze:kounter:$version\")\n}\n\nrepositories {\n    jcenter()\n}\n```\n\n## Usage [![](https://img.shields.io/badge/dokka-read-blue)](https://kounter.netlify.app/)\n\n### Counter / MutableCounter\n\nA specialization of the Map class allowing to count objects.\u003cbr/\u003e\nThis is similar to [Guava Multiset](https://guava.dev/releases/19.0/api/docs/com/google/common/collect/Multiset.html)\nor [Python Counter](https://docs.python.org/3.8/library/collections.html#collections.Counter),\ninspired by [older references](https://github.com/python/cpython/blob/ec007cb43faf5f33d06efbc28152c7fdcb2edb9c/Lib/collections/__init__.py#L516)\nlike [Smalltalk Bag class](http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html).\n\nUsage:\n\n```kotlin\nval lints = mutableCounterOf(\"warnings\" to 20)\n\nlints[\"warnings\"] += 3\nlints[\"errors\"] += 1\n\nprintln(lints) // {warnings=23, errors=1}\n```\n\nHelpers:\n\n```kotlin\ncounterOf(\"aabbbcc\")                    // {a=2, b=3, c=2}\ncounterOf(arrayOf('a', 'b', 'b', 'c'))  // {a=1, b=2, c=1}\ncounterOf(listOf('a', 'a', 'b', 'c'))   // {a=2, b=1, c=1}\ncounterOf(setOf('a', 'b', 'c'))         // {a=1, b=1, c=1}\n```\n\nTo perform mathematical operations on counters, use following methods:\n\n```kotlin\nval c1 = counterOf(\"ab\")\nval c2 = counterOf(\"ccd\")\nc1.plusAll(c2) // {a=2, b=3, c=2}\n\nval chars = mutableCounterOf(\"ab\")\nchars.addAll(counterOf(\"ccd\")) // {a=2, b=3, c=2}\n```\n\n### MapWithDefault / MutableMapWithDefault\n\n**Counter / MutableCounter** are internally using these classes.\n\nThere are also an alternative of\n[withDefault](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/with-default.html)\nwhich is a memory efficient way to specify a default value for a Map but sadly,\nnot reflecting this change in its signature.\u003cbr/\u003e\nIt's forcing users to use an unnatural\n[getValue](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/get-value.html) extension method,\nwhich is not the [most intuitive way of using a Map](https://discuss.kotlinlang.org/t/map-withdefault-not-defaulting/7691).\n\nProposed alternative is slightly changing the original Map interface:\n\n```kotlin\ninterface MapWithDefault\u003cK, V\u003e : Map\u003cK, V\u003e {\n    override fun get(key: K): V\n}\n```\n\nAllowing to unlock a better syntax:\n\n```kotlin\nval money = mutableMapOf(\"Alice\" to 5)\n    .setDefault { 0 }\n\nmoney[\"Alice\"] += 10\nmoney[\"Bob\"] += 3\n\nprintln(money) // {Alice=15, Bob=3}\n```\n\nWhich is shining when used with Set/List/Map:\n\n```kotlin\nval sets = mutableMultiSetWithDefaultOf\u003cString, String\u003e()\n// Alias for mutableMapOf\u003cString, Set\u003cString\u003e\u003e().setDefault { setOf() }\n\nsets += \"Alice\" to setOf(\"f1.txt\")\nsets[\"Bob\"] += setOf(\"f2.md\")\n\nprintln(sets) // {\"A0\"= setOf(\"f1.txt\"), \"A1\"= setOf(\"f2.md\")}\n```\n\nFollowing helpers are available for common native collections:\n\n|      | + setDefault           | Mutable + setDefault          |\n|------|------------------------|-------------------------------|\n| List | multiListWithDefaultOf | mutableMultiListWithDefaultOf |\n| Set  | multiSetWithDefaultOf  | mutableMultiSetWithDefaultOf  |\n| Map  | multiMapWithDefaultOf  | mutableMultiMapWithDefaultOf  |\n\nAlternative: [Guava collection package](https://guava.dev/releases/19.0/api/docs/com/google/common/collect/package-summary.html)\nincluding [Multimap](https://guava.dev/releases/19.0/api/docs/com/google/common/collect/Multimap.html)\nimplemented by [ListMultimap](https://guava.dev/releases/19.0/api/docs/com/google/common/collect/ListMultimap.html)\nor [SetMultimap](https://guava.dev/releases/19.0/api/docs/com/google/common/collect/SetMultimap.html).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgreze%2Fkounter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpgreze%2Fkounter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgreze%2Fkounter/lists"}