Search code examples
kotlinjava-streamreducecollect

Reduce/Collect `List<Map<String, Set<String>` to `Map<String, Set<String>>`


After performing a parallelStream() on a List, I end up with a List<Map<String, Set<String>. I want to unify this into a Map<String, Set<String>> (which will only keep uniques across the List of Maps).

I am unfamiliar with the collect and reduce functions, so don't have anything to go ahead with.

Existing code:

private val TYPES = listOf("string", "integer")

private fun getLinesOfEachTypeAcrossMultipleFiles(files: List<File>): Map<String, Set<String>> {
  return files
    .parallelStream()
    .map { file ->
      TYPES.associate {
        it to getRelevantTypeLinesFromFile(file)
      }
    }
// Converted into a Stream<String, Set<String>>
// .reduce() / collect() ?
}

private fun getRelevantTypeLinesFromFile(it: File): Set<String> {
  // Sample code
  return setOf()
}

Solution

  • I figured out and implemented a Kotlin-specific solution of using the fold operator (instead of reduce or collect):

    private val TYPES = listOf("string", "integer")
    
    private fun getLinesOfEachTypeAcrossMultipleFiles(files: List<File>): Map<String, Set<String>> {
      return files
        .map { file ->
          TYPES.associate { it to getRelevantTypeLinesFromFile(file) }
        }
    
        .fold(mutableMapOf<String, MutableSet<String>>()) { acc, map ->
          acc.apply {
            map.forEach { key, value ->
              acc.getOrPut(key) { mutableSetOf() }.addAll(value)
            }
          }
        }
    }
    
    private fun getRelevantTypeLinesFromFile(it: File): Set<String> {
      // Sample code
      return setOf()
    }
    

    A benefit of using fold is that we don't need to change the type of the data from Map to MutableMap and Set to MutableSet.