How to filter a list down to items matching supplied suffix using Streams in Java 8

Viewed 27

I am new to Java streams but need to master by practice really!

The collection input is made up of strings e.g. [name][dot][country], example as follows:

 - JAMES.BRITAIN
 - JOHN.BRITAIN
 - LEE.BRITAIN
 - GEORGE.FRANCE
 - LEON.FRANCE
 - MARSELLE.FRANCE
 - KOFI.GHANA
 - CHARLIE.GHANA

Given a list of countries, How do I return a list of items whose suffixes matches the supplied countries

So, if I supplied a list parameter containing Britain as item , the resulting list should be:

 - JAMES.BRITAIN
 - JOHN.BRITAIN
 - LEE.BRITAIN

In the real code the streams statement below gives me the list to be filtered i.e.:

List<String> allSolrCollections =  (List<String>) findAllCollections()
                    .getJsonArray(SOLR_CLOUD_COLLECTION)
                    .getList()
                    .stream() 
                    .map(object -> Objects.toString(object, null))
                    .collect(Collectors.toList());

That is:

 - JAMES.BRITAIN
 - JOHN.BRITAIN
 - LEE.BRITAIN
 - GEORGE.FRANCE
 - LEON.FRANCE
 - MARSELLE.FRANCE
 - KOFI.GHANA
 - CHARLIE.GHANA

But, I had to use the following non-stream code to filter by suffice name:

private List<String> getCollectionsFilteredBySuffices(List<String> listParam, List<String> allItemsList) {
         
        List<String> finalList = new ArrayList<>();
        for (String country: listParam) {
             for (String item: allItemsList) {
                if (item.endsWith(country)) {
                    finalList .add(item);
                }
            }
        }
        return finalList ;
    }

Can I do both logic in a single java stream statement e.g.

 List<String> allSolrCollections =  (List<String>) findAllCollections()
                        .getJsonArray(SOLR_CLOUD_COLLECTION)
                        .getList()
                        .filter(//all items with suffices matching content of list param)
                        .stream() 
                        .map(object -> Objects.toString(object, null))
                        .collect(Collectors.toList());
1 Answers

Regardless of the implementation, your method would be more performant if you generate a HashSet of prefixes. That would allow to check each element in the list against this set in constant time.

To achieve it with streams, you need to apply filter() operation, which expects a Predicate and would retain in the stream those elements for which the predicate would be evaluated to true.

Since your data has a structure [name][dot][country], you can use regular expression "[^.]*\\.", which matches zero or more symbols distinct from a dot followed by a dot, to extract the suffix that corresponds to a country.

That's how it might be implemented.

private List<String> getCollectionsFilteredBySuffices(List<String> listParam,
                                                      List<String> allCollections) {

    Set<String> suffixes = new HashSet<>(listParam);
    
    return allCollections.stream()
        .filter(s -> suffixes.contains(s.replaceAll("[^.]*\\.", "")))
        .collect(Collectors.toList()); // or .toList() for Java 16+
}

Here's a single-statement solution (if you want the code to be consice at all costs):

return allCollections.stream()
    .filter(s -> listParam.contains(s.replaceAll("[^.]*\\.", "")))
    .collect(Collectors.toList());
Related