input | output |
---|---|
a | a000 |
Robert | R163 |
Ashcraft | A261 |
Tymczak | T522 |
Pfister | P236 |
테스트 클래스 SoundEXTest를 작성하고
Caller Create 방식으로 프로덕션 클래스인 SoundEX를 생성한다.
가장 간단한 테스트부터 실행한다.
public class SoundEXTest { SoundEX se = new SoundEX(); @Test public void testX() { assertEquals("a", se.convertName("a")); } } |
public String convertName(String inputName) { return "a"; } |
없음
@Test public void testX() { assertEquals("a", se.convertName("a")); assertEquals("b", se.convertName("b")); } |
가장 간단하게 통과시키는 것이므로 "b"가 들어왔을때 "b000"을 반환시키도록 한다.
public String convertName(String inputName) { if (inputName == "b") { return "b"; } return "a"; } |
공백에서 중복을 찾아내면 아래와 같다.
public String convertName(String inputName) { if (inputName == "b") { return "b"; } if (inputName == "a") { return "a"; } return ""; } |
반환값에 적절한 이름인 result를 붙여준다.
public String convertName(String inputName) { String result = ""; if (inputName == "b") { result = "b"; } if (inputName == "a") { result = "a"; } return result; } |
앞에 나오는 b와 a는 inputName을 붙여준 것이다.
이제 두 if문 안의 내용이 완전히 동일해졌다.
public String convertName(String inputName) { String result = ""; if (inputName == "b") { result = inputName; } if (inputName == "a") { result = inputName; } return result; } |
if문 내부의 중복을 제거한다
public String convertName(String inputName) { String result = ""; result = inputName; return result; } |
실패하는 테스트 케이스를 작성할 수 없다.
일반화된 솔루션이 제작되었다고 판단한다. (1글자일 경우에)
@Test public void testX() { assertEquals("a", se.convertName("a")); assertEquals("b", se.convertName("b")); assertEquals("c", se.convertName("c")); } |
그렇다면 2글자의 이름을 시도해본다.
doubleNameTest라는 새로운 테스트 케이스를 만든다. (테스트 케이스와 테스트 코드의 차이.. 테스트 케이스는 테스트 메소드인가?)
@Test public void doubleNameTest() { assertEquals("a1", se.convertName("ab")); } |
public String convertName(String inputName) { String result = ""; if (inputName == "ab") { result ="a1"; } else { result = inputName; } return result; } |
아래와 같이 표현할 수 있다.
public String convertName(String inputName) { String result = ""; if (inputName == "ab") { result += "a"; result += "1"; } else { result += inputName; } return result; } |
반복되는 result+="0";을 반복문을 이용하여 표현한다.
public String convertName(String inputName) { String result = ""; if (inputName == "ab") { result += "a"; result += "1"; } else { result += inputName; } return result; } |
result에 맨 처음 더해주는 값은 inputName의 첫번째 알파벳이다.
따라서 아래와 같이 표현한다.
점점 중복의 형태를 띄고 있다.
public String convertName(String inputName) { String result = ""; if (inputName == "ab") { result += inputName.charAt(0); result += "1"; } else { result += inputName.charAt(0); } return result; } |
위쪽 if문에서 result+="1";은 무엇인가
inputName의 두번째 글자인 b가 치환 요구사항에 따라 치환된 값이다.
따라서 치환 요구사항을 처리해주는 기능을 작성한다.
public String getCode(char ch) { String result = ""; switch (ch) { case 'b': case 'f': case 'p': case 'v': result = "1"; break; case 'c': case 'g': case 'j': case 'k': case 's': case 'x': case 'z': result = "2"; break; case 'd': case 't': result = "3"; break; case 'l': result = "4"; break; case 'm': case 'n': result = "5"; break; case 'r': result = "6"; break; } return result; } |
public String convertName(String inputName) { String result = ""; if (inputName == "ab") { result += inputName.charAt(0); result += getCode(inputName.charAt(1)); } else { result += inputName.charAt(0); } return result; } |
inputName이 2글자인 경우와 1글자인 경우로 구분한다.
public String convertName(String inputName) { String result = ""; if (inputName.length() == 2) { result += inputName.charAt(0); result += getCode(inputName.charAt(1)); } if (inputName.length() == 1) { result += inputName.charAt(0); } return result; } |
aa를 입력하면 getCode에는 모음을 변환하는 기능이 아직 없기 때문에 오류가 난다.
모음과 (h,w)는 중복 제거에서 각각 따로 처리해야 하므로 구분을 해줘야 한다.
@Test public void doubleNameTest() { assertEquals("a1", se.convertName("ab")); assertEquals("a2", se.convertName("ac")); assertEquals("a3", se.convertName("ad")); assertEquals("aa", se.convertName("aa")); // 오류 } |
모음인지 h,w인지에 따라 따로 처리를 해줘야 되기 때문에 getCode를 모음이면 "a" (h, w)이면 "h"로 반환하도록 한다. (모음끼리 구별하거나 h,w끼리 구별하는 것은 의미가 없다)
public String getCode(char ch) { String result = ""; switch (ch) { case 'b': case 'f': case 'p': case 'v': result = "1"; break; case 'c': case 'g': case 'j': case 'k': case 's': case 'x': case 'z': result = "2"; break; case 'd': case 't': result = "3"; break; case 'l': result = "4"; break; case 'm': case 'n': result = "5"; break; case 'r': result = "6"; break; //모음 처리 case 'a': case 'e': case 'i': case 'o': case 'u': result = "a"; break; //h, w 처리 case 'h': case 'w': result = "h"; break; } return result; } |
3개의 이름을 변환 시도한다.
이름이 3개일 경우의 처리는 아직 프로덕션 코드에 없으므로 테스트 케이스는 실패한다.
@Test public void threeNameTest() { assertEquals("a12", se.convertName("abc")); } |
3글자일때도 이전 방식과 동일하게 적용해준다.
3번째 글자에도 변환 과정을 동일하게 적용해준다.
public String convertName(String inputName) { String result = ""; if (inputName.length() == 3) { result += inputName.charAt(0); result += getCode(inputName.charAt(1)); result += getCode(inputName.charAt(2)); } if (inputName.length() == 2) { result += inputName.charAt(0); result += getCode(inputName.charAt(1)); } if (inputName.length() == 1) { result += inputName.charAt(0); } return result; } |
getCode로 변환시키는 중복된 과정을 반복문을 이용하여 바꾸면 아래와 같다.
public String convertName(String inputName) { String result = ""; if (inputName.length() == 3) { result += inputName.charAt(0); for (int i = 1; i < 3; i++) { result += getCode(inputName.charAt(i)); } } if (inputName.length() == 2) { result += inputName.charAt(0); for (int i = 1; i < 2; i++) { result += getCode(inputName.charAt(i)); } } if (inputName.length() == 1) { result += inputName.charAt(0); for (int i = 1; i < 1; i++) { result += getCode(inputName.charAt(i)); } } return result; } |
반복문의 최대 반복횟수는 현재 inputName의 길이와 같다.
public String convertName(String inputName) { String result = ""; if (inputName.length() == 3) { result += inputName.charAt(0); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } } if (inputName.length() == 2) { result += inputName.charAt(0); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } } if (inputName.length() == 1) { result += inputName.charAt(0); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } } return result; } |
각 if문의 내부가 완전히 동일해졌으므로 통일한다.
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } return result; } |
여러가지 케이스를 시도해봐도 실패하는 테스트 케이스를 찾을 수 없다.
따라서 치환하는 기능에 대한 일반적인 솔루션이 작성되었다고 판단한다.
@Test public void threeNameTest() { assertEquals("a12", se.convertName("abc")); assertEquals("a1a", se.convertName("aba")); assertEquals("aaa", se.convertName("aae")); assertEquals("ahh", se.convertName("ahw")); } |
중복을 제거하는 기능을 작성한다.
@Test public void removeDuplicationTest() { assertEquals("a1213", se.removeDuplication("a1122113")); } |
public String removeDuplication(String duplicatedString) { String result = ""; if (duplicatedString == "a1122113") { result = "a1213"; } return result; } |
중복이 제거되는 기능은 아래와 같은 과정을 거친다.
public String removeDuplication(String duplicatedString) { String result = ""; if (duplicatedString == "a1122113") { result += "a"; result += "1"; result += "2"; result += "1"; result += "3"; } return result; } |
public String removeDuplication(String duplicatedString) { String result = ""; if (duplicatedString == "a1122113") { result += duplicatedString.charAt(0); result += duplicatedString.charAt(1); result += duplicatedString.charAt(3); result += duplicatedString.charAt(5); result += duplicatedString.charAt(7); } return result; } |
public String removeDuplication(String duplicatedString) { String result = ""; if (duplicatedString == "a1122113") { result += duplicatedString.charAt(0); result += duplicatedString.charAt(1); result += duplicatedString.charAt(3); result += duplicatedString.charAt(5); result += duplicatedString.charAt(7); } return result; } |
public String removeDuplication(String duplicatedString) { String result = ""; if (duplicatedString == "a1122113") { result += duplicatedString.charAt(0); if (duplicatedString.charAt(1) != duplicatedString.charAt(0)) { result += duplicatedString.charAt(1); } if (duplicatedString.charAt(3) != duplicatedString.charAt(2)) { result += duplicatedString.charAt(3); } if (duplicatedString.charAt(5) != duplicatedString.charAt(4)) { result += duplicatedString.charAt(5); } if (duplicatedString.charAt(7) != duplicatedString.charAt(6)) { result += duplicatedString.charAt(7); } } return result; } |
public String removeDuplication(String duplicatedString) { String result = ""; if (duplicatedString == "a1122113") { result += duplicatedString.charAt(0); if (duplicatedString.charAt(1) != duplicatedString.charAt(0)) { result += duplicatedString.charAt(1); } if (duplicatedString.charAt(2) != duplicatedString.charAt(1)) { result += duplicatedString.charAt(2); } if (duplicatedString.charAt(3) != duplicatedString.charAt(2)) { result += duplicatedString.charAt(3); } if (duplicatedString.charAt(4) != duplicatedString.charAt(3)) { result += duplicatedString.charAt(4); } if (duplicatedString.charAt(5) != duplicatedString.charAt(4)) { result += duplicatedString.charAt(5); } if (duplicatedString.charAt(6) != duplicatedString.charAt(5)) { result += duplicatedString.charAt(6); } if (duplicatedString.charAt(7) != duplicatedString.charAt(6)) { result += duplicatedString.charAt(7); } } return result; } |
중복을 반복문으로 제거하면 아래와 같다.
public String removeDuplication(String duplicatedString) { String result = ""; if (duplicatedString == "a1122113") { result += duplicatedString.charAt(0); for (int i = 1; i < 8; i++) { if (duplicatedString.charAt(i) != duplicatedString .charAt(i - 1)) { result += duplicatedString.charAt(i); } } } return result; } |
8은 duplicationString의 길이를 의미하므로 length로 바꿔주고
duplicationString.charAt(i-1);은 이전 문자와 비교한다는 뜻이므로
previousChar변수를 추가하여 가독성을 명확하게 한다.
public String removeDuplication(String duplicatedString) { String result = ""; char previousChar; if (duplicatedString == "a1122113") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.charAt(0)).charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } } return result; } |
@Test public void removeDuplicationTest() { assertEquals("a1213", se.removeDuplication("a1122113")); assertEquals("a121312", se.removeDuplication("a111112221312")); } |
이전의 코드를 그대로 써도 통과된다.
public String removeDuplication(String duplicatedString) { String result = ""; char previousChar; if (duplicatedString == "a111112221312") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.charAt(0)).charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } } if (duplicatedString == "a1122113") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.charAt(0)).charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } } return result; } |
if문의 중복된 부분을 통합한다.
public String removeDuplication(String duplicatedString) { String result = ""; char previousChar; if (duplicatedString.contains("a")) { result = "A11"; } else { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } } return result; } |
a가 들어가있을때는 뒤에 오는 문자를 붙인다.
이 기능을 따로 처리하는 구문이 없기 때문에 테스트 코드는 실패한다.
assertEquals("A11", se.removeDuplication("A1a1")); //오류 |
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a11") { result = "A11"; } } |
없다.
assertEquals("A11", se.removeDuplication("A1a1")); assertEquals("A11", se.removeDuplication("A1a11")); //오류 |
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result = "A11"; } if (duplicatedString == "A1a11") { result = "A11"; } } |
중복이 제거된 문자열이 나오는 과정을 하나씩 보면 아래와 같다.
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += "A"; result += "1"; result += "1"; } if (duplicatedString == "A1a11") { result += "A"; result += "1"; result += "1"; } } |
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); result += duplicatedString.charAt(1); result += duplicatedString.charAt(3); } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); result += duplicatedString.charAt(1); result += duplicatedString.charAt(3); } } |
비교 대상 문자와 비교하여 일치하지 않을때만 result에 값이 추가된다.
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); if (duplicatedString.charAt(1) != getCode(duplicatedString.toLowerCase().charAt(0)).charAt(0)) { result += duplicatedString.charAt(1); } if(duplicatedString.charAt(3)!=duplicatedString.charAt(2)) { result += duplicatedString.charAt(3); } } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); if (duplicatedString.charAt(1) != getCode(duplicatedString.toLowerCase().charAt(0)).charAt(0)) { result += duplicatedString.charAt(1); } if(duplicatedString.charAt(3)!=duplicatedString.charAt(2)) { result += duplicatedString.charAt(3); } if(duplicatedString.charAt(4)!=duplicatedString.charAt(3)) { result += duplicatedString.charAt(4); } } |
가독성을 명확하게 하기 위하여 비교 대상 문자를 previousChar에 저장한다.
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { result += duplicatedString.charAt(1); previousChar = duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { result += duplicatedString.charAt(3); previousChar = duplicatedString.charAt(3); } } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { result += duplicatedString.charAt(1); previousChar = duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { result += duplicatedString.charAt(3); previousChar = duplicatedString.charAt(3); } if (duplicatedString.charAt(4) != previousChar) { result += duplicatedString.charAt(4); } } } |
아래의 코드를 보자
A1a1의 3번째 a가 나온 부분에서는 값을 더하지 않고 비교문자만 옮긴 것을 알 수 있다.
if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { result += duplicatedString.charAt(1); previousChar = duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(2); //여기는 왜 순차적으로 더해지지 않았을까? if (duplicatedString.charAt(3) != previousChar) { result += duplicatedString.charAt(3); previousChar = duplicatedString.charAt(3); } } |
따라서 아래와 같은 코드가 생략되었다고 볼 수 있다. (A1a11도 마찬가지)
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { result += duplicatedString.charAt(1); previousChar = duplicatedString.charAt(1); } if (duplicatedString.charAt(2) != 'a') { //추가 result += duplicatedString.charAt(2); } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { result += duplicatedString.charAt(3); previousChar = duplicatedString.charAt(3); } } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { result += duplicatedString.charAt(1); previousChar = duplicatedString.charAt(1); } if (duplicatedString.charAt(2) != 'a') { //추가 result += duplicatedString.charAt(2); } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { result += duplicatedString.charAt(3); previousChar = duplicatedString.charAt(3); } if (duplicatedString.charAt(4) != previousChar) { result += duplicatedString.charAt(4); } } } |
하지만 들어온 문자가 a임에도 불구하고 여전히 비교 문자는 옮겼음을 알 수 있다.
if (duplicatedString.charAt(2) != 'a') { //추가 result += duplicatedString.charAt(2); } previousChar = duplicatedString.charAt(2); |
이를 통해서 비교문자를 옮기는 부분 previousChar = duplicatedString.charAt(2);은 문자가 더해지든 안더해지든 실행됨을 알 수 있다.
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { result += duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(1); if (duplicatedString.charAt(2) != 'a') { result += duplicatedString.charAt(2); } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { result += duplicatedString.charAt(3); } previousChar = duplicatedString.charAt(3); } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { result += duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(1); if (duplicatedString.charAt(2) != 'a') { result += duplicatedString.charAt(2); } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { result += duplicatedString.charAt(3); } previousChar = duplicatedString.charAt(3); if (duplicatedString.charAt(4) != previousChar) { result += duplicatedString.charAt(4); } previousChar = duplicatedString.charAt(4); } } |
그리고 a를 검사하는 부분도 각 검사 구문에 동일하게 적용된다.
이제 각 if검사구문이 동일해졌음을 알 수 있다. 어서 중복을 제거하고싶다.....어서
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { if (duplicatedString.charAt(1) != 'a') result += duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(1); if (duplicatedString.charAt(2) != previousChar) { if (duplicatedString.charAt(2) != 'a') { result += duplicatedString.charAt(2); } } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { if (duplicatedString.charAt(3) != 'a') result += duplicatedString.charAt(3); } previousChar = duplicatedString.charAt(3); } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.charAt(1) != previousChar) { if (duplicatedString.charAt(1) != 'a') result += duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(1); if (duplicatedString.charAt(2) != previousChar) { if (duplicatedString.charAt(2) != 'a') { result += duplicatedString.charAt(2); } } previousChar = duplicatedString.charAt(2); if (duplicatedString.charAt(3) != previousChar) { if (duplicatedString.charAt(3) != 'a') result += duplicatedString.charAt(3); } previousChar = duplicatedString.charAt(3); if (duplicatedString.charAt(4) != previousChar) { if (duplicatedString.charAt(4) != 'a') result += duplicatedString.charAt(4); } previousChar = duplicatedString.charAt(4); } } |
드디어 반복문을 이용하여 중복을 제거한다!
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); for (int i = 1; i < 4; i++) { if (duplicatedString.charAt(i) != previousChar) { if (duplicatedString.charAt(i) != 'a') result += duplicatedString.charAt(i); } previousChar = duplicatedString.charAt(i); } } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); for (int i = 1; i < 5; i++) { if (duplicatedString.charAt(i) != previousChar) { if (duplicatedString.charAt(i) != 'a') result += duplicatedString.charAt(i); } previousChar = duplicatedString.charAt(i); } } } |
각 for문의 최대 반복 횟수인 4와 5는, duplicateString.length()와 같다.
if (duplicatedString.contains("a")) { if (duplicatedString == "A1a1") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { if (duplicatedString.charAt(i) != 'a') result += duplicatedString.charAt(i); } previousChar = duplicatedString.charAt(i); } } if (duplicatedString == "A1a11") { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { if (duplicatedString.charAt(i) != 'a') result += duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(i); } } } |
이제 두개의 if문 내부가 완전히 동일해졌으므로 if문을 제거하고 코드를 통합한다.
if (duplicatedString.contains("a")) { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)).charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { if (duplicatedString.charAt(i) != 'a') result += duplicatedString.charAt(1); } previousChar = duplicatedString.charAt(i); } } |
현재 removeDuplication 메소드의 코드는 아래와 같다
public String removeDuplication(String duplicatedString) { String result = ""; char previousChar; if (duplicatedString.contains("a")) { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)).charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { if (duplicatedString.charAt(i) != 'a') result += duplicatedString.charAt(i); } previousChar = duplicatedString.charAt(i); } } else { result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { result += duplicatedString.charAt(i); } previousChar = duplicatedString.charAt(i); } } return result; } |
a가 포함되어 있을때와 포함되어 있지 않을때의 코드가 거의 같아졌다.
사실 a가 포함되어 있을때만 현재 문자가 a인지 검사하고 더해주는 것이므로 a가 포함되어 있지 않을때와 검사 구문이 똑같다고 할 수 있다.
따라서 두 if else 문도 통합한다.
public String removeDuplication(String duplicatedString) { String result = ""; char previousChar; result += duplicatedString.charAt(0); previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { if (duplicatedString.charAt(i) != 'a') result += duplicatedString.charAt(i); } previousChar = duplicatedString.charAt(i); } return result; } |
하지만 코드를 심플하게 하는 데에는 가독성이 굉장히 중요하다고 배워왔다.
위의 코드는 과연 가독성이 좋다고 할 숫 있을까?
아니다.. if문 내부에 if문이 또 있기 때문에 생각이 굉장히 복잡해지게 된다.
따라서 우리는 가독성을 더 좋게 만들 방법에 대하여 생각해봐야 한다.
가드 클로즈라는 말을 아는가?
아래 코드에서 주석 표시한 if문은 != 논리 연산자를 이용했다.
for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) != previousChar) { //여기 if (duplicatedString.charAt(i) != 'a') //여기 result += duplicatedString.charAt(i); } previousChar = duplicatedString.charAt(i); } |
이것을 반대로 표현하면 아래와 같다.
아무것도 실행하지 않고 바로 previouseChar = duplicateString.charAt( i );를 실행하는 것이다. 그렇다면 이것을 좀 더 단순하게 표현한다면?
for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { //아무것도 하지 않는다. } else { if (duplicatedString.charAt(i) == 'a') { //아무것도 하지 않는다. } else { result += duplicatedString.charAt(i); } } previousChar = duplicatedString.charAt(i); } |
아래처럼 continue를 써서 건너뛴다는 것을 좀더 간단명료하게 표현할 수 있다.
이것을 가드 클로즈라고 한다.
하지만 previouseChar = duplicateString.charAt( i );은 꼭 실행되야 하기 때문에 continue문 위에 들어가야 된다. 이것은 중복 문장이다.
이것을 어떻게 해결하면 좋을까?
for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { previousChar = duplicatedString.charAt(i); continue; } if (duplicatedString.charAt(i) == 'a') { previousChar = duplicatedString.charAt(i); continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } |
생각해보면 현재 문자열이 이전 문자열과 같을때에는 이전 문자열이 비교 문자열에 들어가 있을 테니까 굳이 현재 문자열을 비교문자열에 넣을 필요가 없다.
for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { previousChar = duplicatedString.charAt(i); //불필요하므로 생략 continue; } if (duplicatedString.charAt(i) == 'a') { previousChar = duplicatedString.charAt(i); continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } |
for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { continue; } if (duplicatedString.charAt(i) == 'a') { previousChar = duplicatedString.charAt(i); continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } |
h, w에 대한 테스트 코드 작성
@Test public void removeDuplicationTest() { assertEquals("A1213", se.removeDuplication("A1122113")); assertEquals("A121312", se.removeDuplication("A111112221312")); assertEquals("A11", se.removeDuplication("A1a1")); assertEquals("A11", se.removeDuplication("A1a11")); //h 비교 assertEquals("A1", se.removeDuplication("A1h1")); } |
들어온 문자열에 h가 포함되어 있을때 "A1"반환
public String removeDuplication(String duplicatedString) { String result = ""; result += duplicatedString.charAt(0); char previousChar = getCode(duplicatedString.toLowerCase().charAt(0)) .charAt(0); if (duplicatedString.contains("h")) { result = "A1"; } else { for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { continue; } if (duplicatedString.charAt(i) == 'a') { previousChar = duplicatedString.charAt(i); continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } return result; } |
A1h1에서 A1이 나온 이유는 무엇일까?
h는 a와 똑같은 원리로 사라질 것이다.
하지만 h뒤에 나오는 1이 사라진 이유는?
h전에 나왔던 1과 비교를 한 것이다.
그렇다면 h가 나왔을때 비교대상 문자열을 옮기지 않았다는 것이다.
a였을때의 처리 코드를 그대로 가져와서 'h'와 비교하는 부분과 비교문자열을 옮기는 부분을 수정했다.
if (duplicatedString.contains("h")) { for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { continue; } if (duplicatedString.charAt(i) == 'h') { // previousChar = duplicatedString.charAt(i); continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } |
이제 두 소스의 형태가 비슷해졌다.
if (duplicatedString.contains("h")) { for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { continue; } if (duplicatedString.charAt(i) == 'h') { continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } else { for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { continue; } if (duplicatedString.charAt(i) == 'a') { previousChar = duplicatedString.charAt(i); continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } } |
두 if문을 합친다.
이렇게 중복을 제거하는 기능도 완료되었다.
public String removeDuplication(String duplicatedString) { String result = ""; result += duplicatedString.charAt(0); char previousChar = getCode(duplicatedString.toLowerCase().charAt(0)).charAt(0); for (int i = 1; i < duplicatedString.length(); i++) { if (duplicatedString.charAt(i) == previousChar) { continue; } if (duplicatedString.charAt(i) == 'a') { previousChar = duplicatedString.charAt(i); continue; } if (duplicatedString.charAt(i) == 'h') { continue; } result += duplicatedString.charAt(i); previousChar = duplicatedString.charAt(i); } return result; } |
converName() 메소드에 방금 완성한 중복 제거 기능을 추가시킨다.
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); inputName = inputName.toLowerCase(); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } result = removeDuplication(result); return result; } |
이제 완성된 이름을 4글자로 잘라야 한다.
완성된 이름이 4글자가 안되면 0을 붙인다.
N360이 나와야 하는데 N36이 나온다.
@Test public void cutNameTest() { assertEquals("N360", se.convertName("Nethru")); } |
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); inputName = inputName.toLowerCase(); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } result = removeDuplication(result); if (result.length() == 3) { result += "0"; } return result; } |
4글자를 채워야 하므로 결과값의 길이에 따라 0을 더해준다.
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); inputName = inputName.toLowerCase(); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } result = removeDuplication(result); if (result.length() == 3) { result += "0"; } if (result.length() == 2) { result += "0"; result += "0"; } if (result.length() == 1) { result += "0"; result += "0"; result += "0"; } return result; } |
중복이 보이지만 아직 한가지 케이스가 더 남아 있으므로 중복 제거를 잠시 보류한다.
그것은 결과값이 4보다 큰 경우이다.
H435이 나와야 하지만 H4536이 나온다 (4보다 크다)
@Test public void cutNameTest() { assertEquals("N360", se.convertName("Nethru")); // 문자열의 길이가 4보다 짧을때 assertEquals("H453", se.convertName("HelloNethru")); // 문자열의 길이가 4보다 클때 } |
길이가 4보다 길면 현재에서 4번째 길이까지만 반환한다.
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); inputName = inputName.toLowerCase(); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } result = removeDuplication(result); if (result.length() == 3) { result += "0"; } if (result.length() == 2) { result += "0"; result += "0"; } if (result.length() == 1) { result += "0"; result += "0"; result += "0"; } if (result.length() > 4) { result = result.substring(0, 4); } return result; } |
공백에서 중복을 발견하면 아래와 같다.
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); inputName = inputName.toLowerCase(); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } result = removeDuplication(result); if (result.length() == 3) { result += "0"; result = result.substring(0, 4); } if (result.length() == 2) { result += "0"; result += "0"; result = result.substring(0, 4); } if (result.length() == 1) { result += "0"; result += "0"; result += "0"; result = result.substring(0, 4); } if (result.length() > 4) { result += "0"; result += "0"; result += "0"; result = result.substring(0, 4); } return result; } |
중복을 제거하면 아래와 같다.
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); inputName = inputName.toLowerCase(); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } result = removeDuplication(result)+"000"; result = result.substring(0, 4); return result; } |
이름의 길이를 조절하는 기능은 별개로 adjustNameLength()라는 메소드로 따로 뽑는다.
public String convertName(String inputName) { String result = ""; result += inputName.charAt(0); inputName = inputName.toLowerCase(); for (int i = 1; i < inputName.length(); i++) { result += getCode(inputName.charAt(i)); } result = adjustNameLength(result); return result; } private String adjustNameLength(String result) { result = removeDuplication(result) + "000"; result = result.substring(0, 4); return result; } |
실패하는 테스트 케이스를 작성할 수 없다.
따라서 일반화된 솔루션이 작성되었다고 판단한다.
@Test public void finalTest() { assertEquals("R163", se.convertName("Robert")); assertEquals("A261", se.convertName("Ashcraft")); assertEquals("T522", se.convertName("Tymczak")); assertEquals("P236", se.convertName("Pfister")); } |
[Json] 왜 Json을 쓰는가 (0) | 2015.12.06 |
---|---|
[데이터 마이닝] 데이터마이닝의 개념 및 어떤 것들이 있는지 알아보자 (0) | 2015.12.06 |
[Git] Git 기본 명령어 요약정리 (0) | 2015.12.06 |
[Cucumber] 시나리오 Java 코드로 변환하기 (계좌 예금 및 계좌이체하기) (0) | 2015.12.06 |
[Cucumber] Scenario Outline 기법을 활용하여 시나리오 중복 제거하기 (0) | 2015.12.06 |
댓글 영역