2
votes

I am new to stackoverflow and this is my first question on stackoverflow.

I've a below question in my mind:

Print the value of Output1 and Output2 in such a way that, Output1 should print all the characters present in String1 but not in String2 and Output2 should print all the characters present in String2 but not in String1.

Example: If String1: ABC and String: BC then Output1: A and Output2:

If String1: BC and String: BANGALORE then Output1: C and Output2: ANGALORE

I know this question looks similar to Remove characters from the second string which are present in the first string and Given two strings, str1 and str2 as input, remove all chars from str1 that appear in str2 but here I want to get the result of String1 and String2 as two different strings Output1 and Output2

I've tried below program to achieve this but not sure if this is a good solution or not as I am taking four for loops to get the result.

package com.test.java.program;
import java.util.Scanner;
public class PrintString {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        System.out.println("Enter first input as a string: ");
        String str1 = scanner.nextLine();

        System.out.println("Enter first input as a string: ");
        String str2 = scanner.nextLine();

        System.out.println(printStringOutput(str1, str2));
    }

    private static String printStringOutput(String str1, String str2){

        String strTemp1 = str1;

        int strLen1 = str1.length();
        int strLen2 = str2.length();

        for(int i=0; i<strLen1; i++){

            for(int j=0; j<strLen2; j++){

                if(str1.charAt(i) == (str2.charAt(j))){
                    str1 = str1.replace(str1.charAt(i), '\u0000');
                }
            }
        }

        for(int i=0; i<strLen2; i++){

            for(int j=0; j<strLen1; j++){

                if(str2.charAt(i) == (strTemp1.charAt(j))){
                    str2 = str2.replace(str2.charAt(i), '\u0000');
                }
            }
        }

        return "Output1: " + str1 + "\nOutput2: " + str2;
    }
}

I know we can achieve the same result using regex expression as well but not sure how to do it. Could someone please provide a better solution for this question.

I am assuming given inputs are Strings and not performing any validations on inputs.

Thanks.

3
"Could someone please provide a better solution" -- That is not how StackOverflow works. Please visit the help center and read How to Ask. What is "better"? What does not work currently?Jim Garrison
"I have a question on my mind"? Is that your way of obfuscating that you're trying to get help here doing your homework?clearlight
@clearlight: Actually this question was asked to me by one of my colleague at my workplace and I came up with above solution. I know this is a correct one but not a efficient way to get the desired output.Karan Mhetre
@Jim Garrison : This is working perfectly fine but I was looking for a solution which would be better in terms of performance as answered by Andreas. I missed to mention 'in terms of performance' in my question. :(Karan Mhetre
Then the question is off-topic here and belongs on Code ReviewJim Garrison

3 Answers

2
votes

The other two answers (so far) produces 1-character strings as intermediate objects, which is not very efficient.

Building on Dmitry Gorkovets's answer, here is a better version:

String result1 = str1.chars()
                     .filter(ch -> str2.indexOf(ch) < 0)
                     .collect(StringBuilder::new,
                              (buf, ch) -> buf.append((char) ch),
                              StringBuilder::append)
                     .toString();

UPDATE

As mentioned by Jakub M., if str2 can be a long string, you'd get better performance by converting the String to a Map of characters, like this:

Set<Integer> set = str2.chars()
                       .boxed()
                       .collect(Collectors.toSet());

String result1 = str1.chars()
                     .filter(ch -> ! set.contains(ch))
                     .collect(StringBuilder::new,
                              (buf, ch) -> buf.append((char) ch),
                              StringBuilder::append)
                     .toString();
0
votes

Well I don't see any problems in your code, it works. But if you want to use Java 8 features you can use this code:

String str1 = "BC";
String str2 = "BANGALORE";

String result1 = str1.chars()
        .mapToObj(i -> (char)i)
        .filter(c -> str2.indexOf(c) < 0)
        .map(String::valueOf)
        .collect(Collectors.joining());

String result2 = str2.chars()
        .mapToObj(i -> (char)i)
        .filter(c -> str1.indexOf(c) < 0)
        .map(String::valueOf)
        .collect(Collectors.joining());

System.out.println(result1);
System.out.println(result2);
0
votes

Using streams you could do it like this:

Stream.of(str1.split(""))
      .filter((a)->!str2.contains(a))
      .forEach(System.out::print);

Stream.of(str2.split(""))
      .filter((a)->!str1.contains(a))
      .forEach(System.out::print);