andrei1986
andrei1986

Reputation: 35

Convert multiple for loops with conditional logic to Java 8 streams

I need to convert this code containing multiple for loops and if statements to Java 8 Streams:

public static List<String> removeDuplicateNames(String[] namesArray){
  List<String> uniqueNames = new ArrayList<>();
        int occurrence  = 0;
        for(String name:  namesArray) {
            for (String name2 : namesArray)
                if (name.equalsIgnoreCase(name2))
                    occurrence++;
            if (occurrence == 1)
                uniqueNames.add(name);
            occurrence = 0;
        }
  return uniqueNames;
}

I need to loop through an array of names and return a list containing only the names that are not duplicate. If a name appears more than once I need to remove it from the final List.

Input -> ["Tom", "George", "Tom", "Mike", "Brian"]

Output -> ["George", "Mike", "Brian"]

Can anyone please help out?

Upvotes: 0

Views: 463

Answers (3)

Ashutosh Singh
Ashutosh Singh

Reputation: 11

List<String> names = Arrays.asList("Tom", "George", "Tom", "Mike", "Brian");
        Set<String> namesHavingOnlyOneOccurrence = names.stream().collect(Collectors.groupingBy(o -> o)).entrySet()
                .stream()
                .filter(stringListEntry -> stringListEntry.getValue().size() == 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toSet());

Upvotes: 1

Eran
Eran

Reputation: 393781

You can group the names which are equal according to equalsIgnoreCase (by converting all the Strings to lower case), and keep only the groups of size 1:

public static List<String> removeDuplicateNames(String[] namesArray){
    return Arrays.stream(namesArray)
                 .collect(Collectors.groupingBy(String::toLowerCase))
                 .values()
                 .stream()
                 .filter(l -> l.size() == 1)
                 .map(l -> l.get(0)) // or .flatMap(List::stream)
                 .collect(Collectors.toList());
}

Test:

System.out.println(removeDuplicateNames(new String[] {"This", "is", "a", "test", "A", "better", "Test"}));

Output:

[better, This, is]

Upvotes: 0

Andreas
Andreas

Reputation: 159086

You build a map of name to frequency count, then get the names with a count of 1.

That is actually also what your non-stream code should have been doing, for better performance.

public static List<String> removeDuplicateNames(String... namesArray) {
    return Stream.of(namesArray)
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet().stream()
            .filter(e -> e.getValue() == 1)
            .map(Entry::getKey)
            .collect(Collectors.toList());
}

Test

System.out.println(removeDuplicateNames("This", "is", "a", "test", "a", "real", "good", "test"));

Output

[This, is, real, good]

Upvotes: 1

Related Questions