gil.fernandes
gil.fernandes

Reputation: 14611

Replacing stream collect in Kotlin native solution

I am currently using a Kotlin function to extract a map out of a Json structure with key value pairs.

The JSON used to build the map is contains a label and a value:

"values": [
{
  "label": "Email",
  "value": "email"
},
{
  "label": "Social media",
  "value": "socialMedia"
},
{
  "label": "Word of mouth",
  "value": "wordOfMouth"
},
{
  "label": "Newspaper",
  "value": "newspaper"
}
],

The JSON "label" should become the key of the map and the "value" its value.

This is the code used to extract and convert the JSON to a map using Java 8's stream collect method.

fun extractValue(jsonNode: JsonNode?): Map<String, String> {
    val valuesNode = jsonNode?.get("values") ?: mapper.createArrayNode()
    return valuesNode.map { Pair(it.get("label")?.asText() ?: "", it.get("value")?.asText() ?: "") }
            .stream().collect({ HashMap<String, String>()}, { m, p -> m.put(p.first, p.second) } , { m, p -> })
}

How do you write the part with stream().collect in idiomatic Kotlin? What alternatives do you have to replace

stream().collect()

in this specific case?

Upvotes: 3

Views: 888

Answers (3)

Sam
Sam

Reputation: 9944

So you have a list of pairs and you want to convert it to a map? You can just replace your .stream().collect(...) with Kotlin's toMap(). From the Kotlin docs:

fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V>

Returns a new map containing all key-value pairs from the given collection of pairs.

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-map.html

Upvotes: 3

holi-java
holi-java

Reputation: 30686

the associateBy method is like as java Collectors#toMap, so you can simply done it in kotlin as below:

fun extractValue(jsonNode: JsonNode?): Map<String, String> {
    //                              key mapping  ---v
    return jsonNode?.get("values")?.associateBy({ it.get("label")?.asText()?:"" }){
        it.get("value")?.asText() ?: "" // value mapping
    } ?: emptyMap()
    //   ^--- default value is an empty map
}

Upvotes: 2

zsmb13
zsmb13

Reputation: 89568

I believe a toMap call should work here, as you have an Iterable of Pairs:

valuesNode.map { Pair(it.get("label")?.asText() ?: "", it.get("value")?.asText() ?: "") }.toMap()

Upvotes: 2

Related Questions