0
\$\begingroup\$

Objective

Write a function JoinWithAnd in Java with the following signature:

String JoinWithAnd(String a, String b, String c, String d, String e)

So that:

  1. If no input is provided, it returns an empty string
  2. If any one input is provided, it returns the string as it is
  3. If more than one inputs are provided, it combines all strings with AND in between and returns

The input/output looks something like this:

 -----------------------------------------------------------
|Function Call                             |Returns         |
 -----------------------------------------------------------
|JoinWithAnd(null, null, null, null, null);|“”              |
|JoinWithAnd(“A”, null, null, null, null); |“A”             |
|JoinWithAnd(null, null, “C”, null, null); |“C”             | 
|JoinWithAnd(“A”, “B”, null, null, null);  |“A AND B”       |
|JoinWithAnd(“A”, null, “C”, “D”, null);   |“A AND C AND D” |
 -----------------------------------------------------------

Constraints

  • DO NOT change the method signature
  • DO NOT use arrays
  • DO NOT use StringBuffer or any other type of optimized String variants
  • DO NOT use Java Collection

The closest I could get is:

public class JoinWithAnd {

    private final String infix = " AND ";
    private final String regex = "( AND null)+";

    private String compute(String a, String b, String c, String d, String e) {
        return (a + infix + b + infix + c + infix + d + infix + e).replaceAll(regex, "");
    }

    public static void main(String[] args) {
        JoinWithAnd oj = new JoinWithAnd();
        System.out.println(oj.compute("P", null, "R", "S", null));
    }

}

But this doesn't seem to be sufficient since it uses replaceAll.

Could anyone please suggest in what other ways this problem could be solved keeping all the constraints in mind?

\$\endgroup\$
2
  • \$\begingroup\$ Your code does not handle the case of a non null input string equals to "null". \$\endgroup\$ Commented Dec 28, 2016 at 15:20
  • \$\begingroup\$ You're right! Thanks for pointing that out. \$\endgroup\$ Commented Dec 28, 2016 at 15:28

3 Answers 3

1
\$\begingroup\$

Regex

I think your String.replaceAll(String, String) is fine, as regular expressions don't fall afoul of any of the rules. :) Just watch out for @Bastien Aracil's comment, that you will be removing literal "null" values.

With that said...

Break the rules...?

DO NOT use arrays

DO NOT use StringBuffer or any other type of optimized String variants

These are going to be nearly impossible to conform, since a String is fundamentally a char array, and even a simple "a" + "b" uses an underlying StringBuilder for the concatenation. If one can partially 'hand-wave' the implicit StringBuilder away when using the + operator, I suppose one can also do a smaller 'hand-wave' of the implicit char array modification with String.concat(String):

private static String join(String first, String second) {
    if (first == null || first.isEmpty()) {
        return second == null ? "" : second;
    }
    return second == null ? first : first.concat(" AND ").concat(second);
}

What we do here is to codify our logic as such:

  1. If the first string is either null or empty, we either return second or an empty one.
  2. Afterwards, if the second string is null, we return first, i.e. no concatenation done, or actually perform the concatenation with " AND ".

We then just need to 'recursively' call this with the five arguments, and a null or "" as a 'starter' with a:

private static String joinWithAnd(String a, String b, String c, String d, String e) {
    return join(join(join(join(join(null, a), b), c), d), e);
}

Java 8

Going further, we can just rely on streams (not collections) and StringJoiner (technically not a String 'variant', whatever that means) to get the same output:

private static String joinWithAnd(String a, String b, String c, String d, String e) {
    return Stream.of(a, b, c, d, e)
                .filter(Objects::nonNull)
                .collect(Collectors.joining(" AND "));
}

And, if one is being extra pedantic with the question's language, we can replace Stream.of(T...), technically an array, with multiple Stream.concat(Stream, Stream) calls:

// return Stream.of(a, b, c, d, e)
return Stream.concat(Stream.concat(Stream.concat(Stream.concat(
                Stream.of(a), Stream.of(b)), Stream.of(c)), Stream.of(d)), Stream.of(e))
\$\endgroup\$
0
\$\begingroup\$

One way to comply with a constraint of not using any String API would be by building output using ternary operator as shown below:

public class JoinWithAnd {

    private final String infix = " AND ";

    private String compute(String a, String b, String c, String d, String e) {
        return (((a != null) ? a : "") + ((b != null) ? infix + b : "") + ((c != null) ? infix + c : "")
                + ((d != null) ? infix + d : "") + ((e != null) ? infix + e : ""));
    }

    public static void main(String[] args) {
        JoinWithAnd oj = new JoinWithAnd();
        System.out.println(oj.compute("P", null, "R", "S", null));
    }

}
\$\endgroup\$
0
0
\$\begingroup\$

You can use recursivity: handle the special case where b, c, d and e are null, then try to reach this case by calling again the method.

public static final String DELIMITER = " AND ";

public static String joinWithAnd(String a, String b, String c, String d, String e) {
    if (b==null && c==null && d == null && e == null) {
        return a==null?"":a;
    }
    //recurse to reach the special case above
    //by using (b,c,d,e,null) arguments
    final String end = joinWithAnd(b,c,d,e,null);
    //complete the join with the left out 'a' argument
    return a==null?end:a+DELIMITER+end;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.