{"id":29086450,"url":"https://github.com/surpsg/kombi","last_synced_at":"2025-06-28T00:07:49.359Z","repository":{"id":48498121,"uuid":"126722217","full_name":"SurpSG/Kombi","owner":"SurpSG","description":null,"archived":false,"fork":false,"pushed_at":"2021-08-13T21:08:27.000Z","size":308,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2023-10-20T23:17:52.494Z","etag":null,"topics":["cartesian-product","combination","java","kotlin","performance","subsets"],"latest_commit_sha":null,"homepage":null,"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/SurpSG.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":"2018-03-25T17:30:26.000Z","updated_at":"2023-09-19T10:59:44.000Z","dependencies_parsed_at":"2022-08-30T03:50:44.275Z","dependency_job_id":null,"html_url":"https://github.com/SurpSG/Kombi","commit_stats":null,"previous_names":[],"tags_count":3,"template":null,"template_full_name":null,"purl":"pkg:github/SurpSG/Kombi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SurpSG%2FKombi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SurpSG%2FKombi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SurpSG%2FKombi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SurpSG%2FKombi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SurpSG","download_url":"https://codeload.github.com/SurpSG/Kombi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SurpSG%2FKombi/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262352629,"owners_count":23297690,"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":["cartesian-product","combination","java","kotlin","performance","subsets"],"created_at":"2025-06-28T00:07:48.695Z","updated_at":"2025-06-28T00:07:49.336Z","avatar_url":"https://github.com/SurpSG.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kombi\n[![](https://jitpack.io/v/surpsg/kombi.svg)](https://jitpack.io/#surpsg/kombi)\n[![CI](https://github.com/SurpSG/Kombi/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/SurpSG/Kombi/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/SurpSG/Kombi/branch/master/graph/badge.svg?token=DBG3XreExu)](https://codecov.io/gh/SurpSG/Kombi)\n[![GitHub issues](https://img.shields.io/github/issues/surpsg/kombi)](https://github.com/surpsg/kombi/issues)\n[![GitHub stars](https://img.shields.io/github/stars/surpsg/kombi?style=flat-square)](https://github.com/surpsg/kombi/stargazers)\n![GitHub all releases](https://img.shields.io/github/downloads/surpsg/kombi/total)\n\n**Kombi** is able to generate\n* all possible [combinations](https://en.wikipedia.org/wiki/Combination) from given set of items\n* [cartesian product](https://en.wikipedia.org/wiki/Cartesian_product) from given sets of items\n\n**Kombi** advantages:\n* All items computations are lazy that provides a small memory footprint\n* tiny library(~30Kb)\n* no external dependencies\n\nTo get even better throughput(see [Benchmarking](#benchmarking) section), computations can be easily parallelized by splitting to equal independent subsets(see [Parallel computation](#parallel-computation) section).    \n\n## Installation\n### Maven \n```xml\n\u003crepositories\u003e\n    \u003crepository\u003e\n        \u003cid\u003ejitpack.io\u003c/id\u003e\n        \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n    \u003c/repository\u003e\n\u003c/repositories\u003e\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.github.surpsg\u003c/groupId\u003e\n      \u003cartifactId\u003ekombi\u003c/artifactId\u003e\n      \u003cversion\u003e3.1.0\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n### Gradle\n```groovy\nrepositories {\n    maven { url 'https://jitpack.io' }\n}\n\ndependencies {\n    compile 'com.github.surpsg:kombi:3.1.0'\n}\n```\n## Combinations\n`Combination\u003cCollection\u003cT\u003e` is an iterable object, so you can use it in 'for-each' loop.\nTo get items lazily you can use the iterator by calling `iterator()` function or you can get them as the stream by calling `stream()` function. \n### Usage for lists\n```java\n    List\u003cString\u003e inputData = Arrays.asList(\"A\", \"B\", \"C\");\n    \n    Combination\u003cList\u003cString\u003e\u003e combinations = CombinationsBuilder.combinationsOf(inputData);\n    combinations.stream().forEach(System.out::println);\n```\nThe output:\n```\n    [A]\n    [B]\n    [A, B]\n    [C]\n    [A, C]\n    [B, C]\n    [A, B, C]\n```\n\n### Usage for maps\n```java\n    Map\u003cInteger, String\u003e data = new HashMap\u003c\u003e();\n    data.put(1, \"1\");\n    data.put(2, \"2\");\n    data.put(3, \"3\");\n    \n    Combination\u003cMap\u003cInteger, String\u003e\u003e cartesianProduct = CombinationsBuilder.combinationsOf(data);\n    cartesianProduct.forEach(System.out::println);\n```\nThe output:\n```\n    {1=1}\n    {2=2}\n    {1=1, 2=2}\n    {3=3}\n    {1=1, 3=3}\n    {2=2, 3=3}\n    {1=1, 2=2, 3=3}\n```\n\n## Cartesian product\n`CartesianProduct\u003cCollection\u003cT\u003e` is an iterable object, so you can use it in 'for-each' loop.\nTo get items lazily you can use the iterator by calling `iterator()` function or you can get them as the stream by calling `stream()` function.\n### Usage for lists\n```java\n    List\u003cList\u003cInteger\u003e\u003e data = Arrays.asList(\n            Arrays.asList(1, 2, 3),\n            Arrays.asList(4, 5),\n            Arrays.asList(6)\n    );\n    \n    CartesianProduct\u003cList\u003cInteger\u003e\u003e cartesianProduct = CartesianBuilder.cartesianProductOf(data, false);\n    cartesianProduct.forEach(System.out::println);\n```\nThe output:\n```\n    [1, 4, 6]\n    [1, 5, 6]\n    [2, 4, 6]\n    [2, 5, 6]\n    [3, 4, 6]\n    [3, 5, 6]\n```\n\n### Usage for maps\n```java\n    Map\u003cInteger, List\u003cInteger\u003e\u003e data = new HashMap\u003c\u003e();\n    data.put(1, Arrays.asList(1, 2, 3));\n    data.put(2, Arrays.asList(4, 5));\n    data.put(3, Arrays.asList(6));\n    \n    CartesianProduct\u003cMap\u003cInteger, Integer\u003e\u003e cartesianProduct = CartesianBuilder.cartesianProductOf(data, true);\n    cartesianProduct.forEach(System.out::println);\n```\nThe output:\n```\n    {1=1, 2=4, 3=6}\n    {1=1, 2=5, 3=6}\n    {1=2, 2=4, 3=6}\n    {1=2, 2=5, 3=6}\n    {1=3, 2=4, 3=6}\n    {1=3, 2=5, 3=6}\n```\n### Performance tip\nThere is an overloaded builder method `CartesianBuilder.cartesianProductOf(..., boolean keepOrder)` that accepts boolean parameter `keepOrder`. By default the parameter is `false` that provides a little bit better performance. See (see [Benchmarking](#benchmarking) section) to compare.\n\n## Parallel computation\n\n```java\n        // generate data for combinations\n        List\u003cInteger\u003e data = IntStream.range(0, 10).boxed().collect(Collectors.toList());\n        Combination\u003cList\u003cInteger\u003e\u003e combinations = CombinationsBuilder.combinationsOf(data);\n\n        int threads = 4;\n        ExecutorService threadPool = Executors.newFixedThreadPool(threads);\n        AtomicInteger count = new AtomicInteger();\n\n        // split to equal parts to compute parallelly\n        List\u003cCombination\u003cList\u003cInteger\u003e\u003e\u003e subSets = combinations.split( threads );\n        for (Combination\u003cList\u003cInteger\u003e\u003e subSet : subSets) {\n            threadPool.submit(() -\u003e {\n                for (List\u003cInteger\u003e combination : subSet) {\n                    // uncomment line below to print computed combination\n                    // System.out.println(combination);\n                    count.incrementAndGet();\n                }\n            });\n        }\n\n        threadPool.shutdown();\n        threadPool.awaitTermination(20, TimeUnit.SECONDS);\n        System.out.println(\"Combinations: \" + count + \", expectedCombinations: \"+combinations.getCombinationsNumber());\n```\n\n## Benchmarking\nMeasured time of generation of combination/cartesian product items (microseconds to generate all items)\n\nFeel free to run benchmarks by yourself:\n```\n./gradlew clean kombi-jmh:jmh\n```\n\n\nBenchmark results(less is better):\n```\nUbuntu 18.04.4 LTS\nIntel® Core™ i7-6500U CPU @ 2.50GHz × 4\n# JMH version: 1.22\n# VM version: JDK 1.8.0_242, OpenJDK 64-Bit Server VM, 25.242-b08\n# VM invoker: /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java\n# VM options: -Xms512m -Xmx1g\n# Warmup: 5 iterations, 10 s each\n# Measurement: 5 iterations, 10 s each\n# Timeout: 10 min per iteration\n# Threads: 1 thread, will synchronize iterations\n# Benchmark mode: Average time, time/op\n\nBenchmark                                                                         (itemsQuantity)  Mode  Cnt        Score        Error  Units\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Lists                             3  avgt   10        0.396 ±      0.002  us/op\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Lists                             5  avgt   10        8.592 ±      0.190  us/op\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Lists                             7  avgt   10      507.613 ±      3.286  us/op\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Lists                            11  avgt   10  6047357.993 ±  11218.642  us/op\nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists                             3  avgt   10        0.363 ±      0.005  us/op\nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists                             5  avgt   10        6.838 ±      0.176  us/op      \nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists                             7  avgt   10      374.914 ±     69.084  us/op\nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists                            11  avgt   10  3360446.209 ±  45311.037  us/op\n\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Sets                              3  avgt   10        0.815 ±      0.066  us/op\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Sets                              5  avgt   10       15.611 ±      0.578  us/op\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Sets                              7  avgt   10      645.309 ±     43.153  us/op\nc.s.b.cartesian.CartesianListBenchmark.Guava_cartesianProduct_Sets                             11  avgt   10  7492806.803 ± 137744.113  us/op\n\nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists_keepingOrder                3  avgt   10        0.449 ±      0.059  us/op\nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists_keepingOrder                5  avgt   10        8.432 ±      0.260  us/op\nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists_keepingOrder                7  avgt   10      407.532 ±      1.454  us/op\nc.s.b.cartesian.CartesianListBenchmark.Kombi_cartesianProduct_Lists_keepingOrder               11  avgt   10  4061078.368 ±  42057.603  us/op\n\nc.s.b.cartesian.CartesianMapBenchmark.Kombi_cartesianProduct_Maps                               5  avgt   10       18.971 ±      1.902  us/op\nc.s.b.cartesian.CartesianMapBenchmark.Kombi_cartesianProduct_Maps                               7  avgt   10     1050.295 ±     20.054  us/op\nc.s.b.cartesian.CartesianMapBenchmark.Kombi_cartesianProduct_Maps_keepingOrder                  5  avgt   10       19.619 ±      2.603  us/op\nc.s.b.cartesian.CartesianMapBenchmark.Kombi_cartesianProduct_Maps_keepingOrder                  7  avgt   10     1212.077 ±    139.650  us/op\n\nc.s.b.combination.CombinationBenchmark.Kombi_combinations_list                                 11  avgt   10      216.704 ±      3.633  us/op\nc.s.b.combination.CombinationBenchmark.Kombi_combinations_list                                 19  avgt   10    77641.630 ±   1561.054  us/op\n\nc.s.b.combination.CombinationBenchmark.Kombi_combinations_map                                  11  avgt   10      467.513 ±      2.014  us/op\nc.s.b.combination.CombinationBenchmark.Kombi_combinations_map                                  19  avgt   10   170390.506 ±   3108.922  us/op\n\n```\nComparing performance with Guava(microseconds per generation, less is better):\n\n![](kombi-jmh/charts/items_39916800.jpg)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurpsg%2Fkombi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsurpsg%2Fkombi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurpsg%2Fkombi/lists"}