Home > Mobile >  Compare two lists and increase the counter on a match with java streams
Compare two lists and increase the counter on a match with java streams

Time:06-22

I have two lists. list1 contains some citiys.

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

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

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

list1 = ["Barcelona", "Milan", "Athens"];
list2 = [["Rom", "Amsterdam", "Vienna"], ["Amsterdam", "Barcelona", "Milan"], ["Prais", "Athens"], ["Istanbul", "Barcelona", "Milan", "Athens"]];

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

Thanks a lot!

CodePudding user response:

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()));

CodePudding user response:

Have a look at the mapToInt() and sum() function.

List<String> list1 = List.of("Barcelona", "Milan", "Athens");
        List<List<String>> list2 = List.of(List.of("Rom", "Amsterdam", "Vienna"),
                                           List.of("Amsterdam", "Barcelona", "Milan"),
                                           List.of("Prais", "Athens"),
                                           List.of("Istanbul", "Barcelona", "Milan", "Athens"));
int result = list2.stream().mapToInt(person -> person.stream().anyMatch(list1::contains) ? 1 : 0).sum();

What I do here is create a stream of all persons and then map each person to either 1 or 0 depending on if any of their visited countries is contained in list1.

This is identical with the following for-loop example:

int result = 0;
for (List<String> person : list2)
{
    int i = 0;
    for (String visited : person)
    {
        if (list1.contains(visited))
        {
            i = 1;
            break;
        }
    }
    result  = i;
}
  • Related