javajava-8java-streamjsonpath

Parsing a Java List<List<LinkedHashMap<String,String>>> using streams


I have parsed the following JSON String using JSON Path:

{
    [
         [
            {
                "ID": "ExternalKey",
                "Name": "ExternalKey",
                "Label": "ExternalKey",
                "ExternalKey": "",
            "TranslatedName": "ExternalKey",
            "Type": "caption",
            "Self": "https://aqb629.saas.contentserv.com/admin/rest/product/Attribute/ExternalKey",
            "Value": "VSCHL01",
            "FormattedValue": "VSCHL01"
            },
            {
            "ID": "PdmarticleID",
            "Name": "PdmarticleID",
            "Label": "PdmarticleID",
            "ExternalKey": "",
            "TranslatedName": "PdmarticleID",
            "Type": "_id",
            "Self": "",
            "Value": 99942,
            "FormattedValue": 99942
            }
        ],
        [
            {
                "ID": "ExternalKey",
                "Name": "ExternalKey",
                "Label": "ExternalKey",
                "ExternalKey": "",
                "TranslatedName": "ExternalKey",
                "Type": "caption",
                "Self": "",
                "Value": "VSCHL02",
                "FormattedValue": "VSCHL02"
            },
            {
                "ID": "PdmarticleID",
                "Name": "PdmarticleID",
                "Label": "PdmarticleID",
                "ExternalKey": "",
                "TranslatedName": "PdmarticleID",
                "Type": "_id",
                "Self": "",
                "Value": 99944,
                "FormattedValue": 99944
            }
        ]
    ] 
}

I get the following List of Lists in Java:

List<List<LinkedHashMap<String,String>>> productsMasterMap = jsonContext.read(jsonPath);

I would like to do a search via streams where for ID = PdmArticleID and Value=99924 I would get the following structure:

[
    {
        "ID": "ExternalKey",
        "Name": "ExternalKey",
        "Label": "ExternalKey",
        "ExternalKey": "",
        "TranslatedName": "ExternalKey",
        "Type": "caption",
        "Self": "https://aqb629.saas.contentserv.com/admin/rest/product/Attribute/ExternalKey",
        "Value": "VSCHL01",
        "FormattedValue": "VSCHL01"
    },
    {
        "ID": "PdmarticleID",
        "Name": "PdmarticleID",
        "Label": "PdmarticleID",
        "ExternalKey": "",
        "TranslatedName": "PdmarticleID",
        "Type": "_id",
        "Self": "",
        "Value": 99942,
        "FormattedValue": 99942
    }
]

Which is a List<LinkedHashMap<String,String>> object. How can I achieve that? I have tried the following:

List<LinkedHashMap> listOfMaps =    

productsMasterMap.stream().filter(listOfHashMaps->
                
listOfHashMaps.stream().filter(m->m.get("ID").equals("PdmarticleID") &&   

m.get("Value").equals("99945"))
                     
map(m->m).collect(Collectors.toList());

I would like to get the inner list element where the condition is true.


Solution

  • You can use Stream.anyMatch() on the inner stream to find if any of the maps matches your condition:

    Returns whether any elements of this stream match the provided predicate. May not evaluate the predicate on all elements if not necessary for determining the result.

    Then you can use Stream.findFirst() to get the first match:

    Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty.

    List<List<LinkedHashMap<String,String>>> productsMasterMap = ...;
    
    Optional<List<LinkedHashMap<String, Object>>> listOfMaps = productsMasterMap.stream()
                .filter(listOfHashMaps -> listOfHashMaps.stream()
                        .anyMatch(map -> map.get("ID").equals("PdmarticleID") && map.get("Value").equals(99944)))
                .findFirst();
    //handle the Optional
    

    If there can be more than 1 match and you care about those matches, instead of findFirst collect to a list.

    As a side note, i would use a custom class, instead of Map, the elements have the same properties. It will make the code much more readable.