0

I want to filter the list by unique elements with case insensitive filtering using java 8.

E.g: 1) Input: Goodbye bye Bye world world WorlD

Output: Goodbye bye world

2) Input: Sam went went to to To his business

Output: Sam went to his business

I tried by following code. I have used distinct() for unique elements and map(x->x.toLowerCase()) so that distinct() will filter unique elements by lowering its case.

    System.out.println("Enter the no of lines u will input:: ");
    Scanner sc = new Scanner(System.in);
    Integer noOfLines = sc.nextInt();
    sc.nextLine();
    List<String> listForInput;
    List<List<String>> allInputs = new ArrayList<>();
    for(int i =0; i<noOfLines; i++)
    {
        String receivedLine = sc.nextLine();

        String[] splittedInput = receivedLine.split(" ");

        List<String> list =  Stream.of(splittedInput)
                .map(x->x.toLowerCase())
                .distinct()
                .collect(Collectors.toList());

        list.forEach(x-> System.out.print(x+" "));

but in the output I get all the elements in lower case. Is there better I can do using java 8 or m I doing something wrong here?

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Vipul
  • 49
  • 8

4 Answers4

2

You are transforming all to lowercase using .map(x->x.toLowerCase()).

You can use a TreeSet to maintain unique and removeIf for removing from list

List<String> list = new ArrayList<>(Arrays.asList(splittedInput));
TreeSet<String> unique = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
list.removeIf(e -> !unique.add(e)); // Check if already have then remove
Eklavya
  • 17,618
  • 4
  • 28
  • 57
  • Have you tested your code? This code throws an `UnsupportedOperationException`, because `Arrays.asList` returns a list backed by the underlying array, so its size cannot be changed. (Use `new ArrayList<>(Arrays.asList(...))` in order to fix it.) By the way, the output is different of OP's expected output, as in that the words are sorted alphabetically. – MC Emperor Jun 17 '20 at 16:06
  • @MCEmperor Thanks for pointing out. `list` won't be sorted here, it will be the same order as OP wants. – Eklavya Jun 17 '20 at 16:47
1

You can try below solution with Java-8

System.out.println("Enter the no of lines u will input:: ");
        Scanner sc = new Scanner(System.in);
        Integer noOfLines = sc.nextInt();
        sc.nextLine();
        List<List<String>> allInputs = new ArrayList<>();
        for (int i = 0; i < noOfLines; i++) {
            String receivedLine = sc.nextLine();

            List<String> list = Stream.of(Pattern.compile("\\s").splitAsStream(receivedLine)
                    .collect(Collectors.collectingAndThen(
                            Collectors.toMap(String::toLowerCase, Function.identity(), (l, r) -> l, LinkedHashMap::new),
                            m -> String.join(" ", m.values())))
                    .split(" ")).collect(Collectors.toList());

            list.forEach(x -> System.out.print(x + " "));

        }
SSK
  • 3,444
  • 6
  • 32
  • 59
  • 1
    Splitting the string, joining it, and then splitting it again? That looks unnecessary to me. If you replace `m -> String.join(" ", m.values())` with `m -> new ArrayList<>(m.values())`, you can remove the `Stream.of(` and the `.split(" ")).collect(Collectors.toList())`. – MC Emperor Jun 17 '20 at 16:38
  • Yes, @MC Emperor you are correct, we can modify this code as per our requirements – SSK Jun 18 '20 at 04:37
1

Here is another way to do it. While the usecase is slightly different, this proposed solution is the same as this answer by Stuart Marks.

In essence, you want to apply a stateful filter: you want to discard certain elements based on elements already seen before. This is more or less what distinct() does, however, distinct() is restricted to the equals method. The following method provides a Predicate which maintains state:

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

The desired can then be achieved using the following:

Arrays.stream(receivedLine.split(" "))
    .filter(distinctByKey(String::toLowerCase))
    .collect(Collectors.toList());
MC Emperor
  • 22,334
  • 15
  • 80
  • 130
0

You can make use of LinkedHashSet like below,

for(int i =0; i<noOfLines; i++)
        {
            String receivedLine = sc.nextLine();

            String[] splittedInput = receivedLine.toLowerCase().split(" ");

            Set<String> list =  new LinkedHashSet<>(Arrays.asList(splittedInput));

            list.forEach(x-> System.out.print(x+" "));
         }
Adithya
  • 19
  • 1