Search code examples
javacountjava-streamcompare

Count number of lists that contain an element from another list using the Java Stream API


I have two lists.

list1 contains some cities.

list2 contains sub-lists of cities. Each sub-list contains the cities already visited by a person (one sub-list = the cities visited by one person). In the example Person1 has traveld to Rome, Amsterdam and Vienna, Person2 to Amsterdam, Barcelona and Milan ...

I would like to know how many people have already been to the cities in the first list. There should be no double counting. So if Person1 has already been to two cities from list1, it should only be counted once.

I would like to implement this with the Java Stream API. Does anyone know how I can do this?

list1 = ["Barcelona", "Milan", "Athens"];
list2 = [["Rome", "Amsterdam", "Vienna"], ["Amsterdam", "Barcelona", "Milan"], ["Paris", "Athens"], ["Istanbul", "Barcelona", "Milan", "Athens"]];

//The expected result for this example is: 3
//Both lists already result from a stream (Collectors.toList())

Solution

  • You can try something like this:

        private static final List<String> CITIES = List.of("Barcelona", "Milan", "Athens");
        private static final List<List<String>> VISITED_CITIES = List.of(
                List.of("Rome", "Amsterdam", "Vienna"),
                List.of("Amsterdam", "Barcelona", "Milan"),
                List.of("Paris", "Athens"),
                List.of("Instabul", "Barcelon", "Milan", "Athens")
        );
    
        public static void main(String... args) {
            var count = VISITED_CITIES
                    .stream()
                    .flatMap(visited -> visited.stream().filter(CITIES::contains))
                    .distinct()
                    .count();
            System.out.println(count);
        }
    

    With this iteration you will get the expected result of 3. However you can modify your code to also collect into a Map that will show frequencies (if you remove the distinct intermediate step), something like this:

            var count = VISITED_CITIES
                    .stream()
                    .flatMap(visited -> visited.stream().filter(CITIES::contains))
                    .collect(Collectors.groupingBy(Function.identity()));