I am doing the following programming exercise: Merged String Checker
1) I have tried the following code:
import java.util.*;
public class StringMerger {
public static boolean isMerge(String s, String part1, String part2) {
System.out.println("\n\ns: "+s);
System.out.println("part1: "+part1);
System.out.println("part2: "+part2);
if(!s.isEmpty() && part1.isEmpty() && part2.isEmpty()) return false;
if( ( part1==null || part1.isEmpty() && part2.equals(s) ) || part2==null || part2.isEmpty() && part1.equals(s) ){
return true;
}
/*Check if complete words from s are in part1 or part2*/
List<String> sList = new ArrayList(Arrays.asList(s.split(" ")));
List<String> part1List = new ArrayList(Arrays.asList(part1.split(" ")));
List<String> part2List = new ArrayList(Arrays.asList(part2.split(" ")));
System.out.println("sList: "+Arrays.toString(sList.toArray()));
System.out.println("part1List: "+Arrays.toString(part1List.toArray()));
System.out.println("part2List: "+Arrays.toString(part2List.toArray()));
for(Iterator<String> it = sList.iterator(); it.hasNext(); ){
String word = it.next();
if(word.equals(part1List.get(0))){
it.remove();
part1List.remove(0);
System.out.println("sList: "+Arrays.toString(sList.toArray()));
System.out.println("part1List: "+Arrays.toString(part1List.toArray()));
}else if(word.equals(part2List.get(0))){
it.remove();
part2List.remove(0);
System.out.println("sList: "+Arrays.toString(sList.toArray()));
System.out.println("part2List: "+Arrays.toString(part2List.toArray()));
}
}
s=String.join(" ",sList);
part1=String.join(" ",part1List);
part2=String.join(" ",part2List);
System.out.println("\n\ns: "+s);
System.out.println("part1: "+part1);
System.out.println("part2: "+part2);
/*Check if s first character is part1 or part2 initial character*/
for(char letter : s.toCharArray()){
System.out.println("letter: "+letter);
System.out.println("part1: "+part1);
System.out.println("part2: "+part2);
if(!part1.isEmpty() && letter == part1.charAt(0)){
part1 = part1.substring(1);
System.out.println("part1: "+part1);
s = s.substring(1);
}else if(!part2.isEmpty() && letter==part2.charAt(0)){
part2 = part2.substring(1);
System.out.println("part2: "+part2);
s = s.substring(1);
}
System.out.println("s: "+s);
System.out.println("s.substring(0,part1.length()): "+s.substring(0,part1.length()));
if(s.substring(0,part1.length()).equals(part1)){
s=s.substring(part1.length());
part1="";
System.out.println("are equal, s: "+s);
}else if(s.substring(0,part2.length()).equals(part2)){
s=s.substring(part2.length());
part2="";
System.out.println("are equal, s: "+s);
}
if(s.isEmpty() || (part1.length()==0 && part2.length()==0) ) break;
}
System.out.println("\n\ns: "+s);
System.out.println("part1: "+part1);
System.out.println("part2: "+part2);
return s.isEmpty() && part1.isEmpty() && part2.isEmpty();
}
}
And I would like you to explain: why does it fail the following test‽
import org.junit.Test;
import static org.junit.Assert.*;
public class StringMergerTest {
@Test
public void suffledPartsLetters(){
assertTrue("",StringMerger.isMerge("Can we merge it? Yes, we can!","nwe me?s, e cn","Ca erg it Yewa!"));
}
}
I have identified in the trace where is behaves unexpectedly:
letter: **r**
part1: ?s, e cn
part2: e**r**g it Yewa!
s: rge it? Yes, we can!
s.substring(0,part1.length()): rge it?
letter: **g**
part1: ?s, e cn
part2: er**g** it Yewa!
s: rge it? Yes, we can!
s.substring(0,part1.length()): rge it?
I understand that letter r and g are not being detected because of the code just checks if it is the first character in part1 or part2.
However I do not fully understand how could we fix the previous code to let it handle this case, could you help me please?
Besides I have also researched and found this post which describes some exercises' javascript solutions:
CodeWars/ Merged String Checker
I tried to write the recursive one without looking at the solution, and I came up with:
public class StringMerger {
public static boolean isMerge(String s, String part1, String part2) {
System.out.println("\n\ns: "+s);
System.out.println("part1: "+part1);
System.out.println("part2: "+part2);
if(s.length()!= (part1.length()+part2.length()) ){
System.out.println("lengths are different");
return false;
}
if(s.length()==0) {
System.out.println("s.length is 0");
return true;
}
if(part1.length()>0 && s.charAt(0)==part1.charAt(0)){
System.out.println("s first char is part1 first char");
isMerge(s.substring(1),part1.substring(1),part2);
}
if(part2.length()>0 && s.charAt(0)==part2.charAt(0)){
System.out.println("s first char is part2 first char");
isMerge(s.substring(1),part1,part2.substring(1));
}
return false;
}
}
Why does the previous one fail the following tests?
import org.junit.Test;
import static org.junit.Assert.*;
public class StringMergerTest {
@Test
public void normalHappyFlow() {
assertTrue("codewars can be created from code and wars", StringMerger.isMerge("codewars", "code", "wars"));
assertTrue("codewars can be created from cdwr and oeas", StringMerger.isMerge("codewars", "cdwr", "oeas"));
assertFalse("Codewars are not codwars", StringMerger.isMerge("codewars", "cod", "wars"));
}
@Test
public void suffledPartsLetters(){
assertTrue("",StringMerger.isMerge("Can we merge it? Yes, we can!","nwe me?s, e cn","Ca erg it Yewa!"));
}
}
I expected that when all letters are matched with part1 or part2 letters, and s is empty with length 0, it would output true.
However it outputs false even when it detects s.length is 0.
The trace is:
s: codewars
part1: code
part2: wars
s first char is part1 first char
s: odewars
part1: ode
part2: wars
s first char is part1 first char
s: dewars
part1: de
part2: wars
s first char is part1 first char
s: ewars
part1: e
part2: wars
s first char is part1 first char
s: wars
part1:
part2: wars
s first char is part2 first char
s: ars
part1:
part2: ars
s first char is part2 first char
s: rs
part1:
part2: rs
s first char is part2 first char
s: s
part1:
part2: s
s first char is part2 first char
s:
part1:
part2:
s.length is 0
How could we also fix the previous code? And why does it fails to pass the tests?
I have also read:
Best way to convert an ArrayList to a string ConcurrentModificationException for ArrayList java : remove words from ArrayList<String> Removing items from a list Converting array to list in Java Checking if a string is empty or null in Java