Codewars 문제풀기 (04/27)
Directions Reduction
- String 배열을 인자로 받는다.
- 입력 배열은 “WEST”, “EAST”, “NORTH”, “SOUTH”로 이루어져있다.
- EAST-WEST / NORTH-SOUTH 경로를 제거한 새로운 direction을 리턴한다.
- dirReduc(“NORTH”, “SOUTH”, “SOUTH”, “EAST”, “WEST”, “NORTH”, “WEST”) 👉 NORTH-SOUTH / EAST - WEST삭제 👉 “SOUTH”, “NORTH”, “WEST” 👉 SOUTH - NORTH 삭제 👉 “WEST” 👉 {“WEST”}
- {“NORTH”, “WEST”, “SOUTH”, “EAST”}는 EAST - WEST / NORTH-SOUTH가 붙어있지 않기 때문에 삭제하지 않는다.
1. Test와 리팩토링
-
테스트 1 - 입력 배열이 빈 배열이라면 빈 배열을 리턴한다.
-
테스트 코드
@Test @DisplayName("test should return {} when input {}") public void test1() { // Given: Set array length 0 String[] given = new String[]{}; // When: Call dirReduc method String[] actual = DirReduction.dirReduc(given); // Then: Should return empty array assertArrayEquals(given, actual); }
-
실제 코드
public class DirReduction { public static String[] dirReduc(String[] arr) { return new String[]{}; } }
-
리팩토링 - 테스트 코드 when 삭제
@Test @DisplayName("test should return {} when input {}") public void test1() { // Given: Set array length 0 String[] given = new String[]{}; // Then: Should return empty array assertArrayEquals(given, DirReduction.dirReduc(given)); }
-
-
테스트 2 - 서로 반대되는 direction이 없을 경우 입력 배열 그대로 리턴
-
테스트 코드
@Test @DisplayName("test should return same array when there is no opposite direction") public void test2() { // Given: Set array there is no opposite direction String[] given = new String[]{"SOUTH", "WEST", "NORTH", "EAST"}; // Then: Should return input array assertArrayEquals(given, DirReduction.dirReduc(given)); }
-
실제 코드
public class DirReduction { public static String[] dirReduc(String[] arr) { return arr; } }
- 처음에 이 부분 때문에 계속 실패했다. 문제를 잘못봐서 SOUTH-WEST-NORTH-EAST로 움직이면 결국 제자리에 오니까 이것도 삭제해줘야 되는줄 알았는데 문제 테스트에 계속 실패해서 원인을 찾다보니 문제를 잘못 읽은것이었다 ㅡㅡ..
-
-
테스트 3 - 입력 배열이 {SOUTH, NORTH}라면 empty 배열을 리턴
-
테스트 코드
@Test @DisplayName("test should return {} when input array {SOUTH, NORTH}") public void test3() { // Given: Set array there is only one opposite direction String[] given = new String[]{"SOUTH", "NORTH"}; // Then: Should return empty array assertArrayEquals(new String[]{}, DirReduction.dirReduc(given)); }
-
실제 코드
public class DirReduction { public static String[] dirReduc(String[] arr) { String toString = String.join(" ", arr); toString = toString.replace("SOUTH NORTH", "").trim(); return toString.length()==0? new String[]{} : arr; } }
- 여기서 삽질을 많이했다. if / else if문이나 switch문을 사용하려 했는데 코드가 많이 더러워질것 같아서 결국 String으로 바꾸고 replace를 이용해서 삭제하기로 했다.
-
-
테스트 4 - 입력 배열이 {NORTH, SOUTH, EAST}라면 {EAST} 리턴
-
테스트 코드
@Test @DisplayName("test should return {EAST} when input array {NORTH, SOUTH, EAST}") public void test4() { // Given: Set array {"NORTH", "SOUTH", "EAST"} String[] given = new String[]{"NORTH", "SOUTH", "EAST"}; // Then: Should return {"EAST"} assertArrayEquals(new String[]{"EAST"},DirReduction.dirReduc(given)); }
-
실제 코드
public class DirReduction { public static String[] dirReduc(String[] arr) { String toString = String.join(" ", arr); toString = toString.replace("SOUTH NORTH", "") .replace("NORTH SOUTH", "").trim(); if (toString.length() == 0) { return new String[]{}; } return toString.split(" "); } }
replace()
메서드로 SOUTH NORTH, NORTH SOUTH를 삭제하면 EAST만 남기 때문에 “EAST”를 String 배열로 만들어 리턴했다.
-
리팩토링 - 상수 추출
//실제 코드 public static final String SOUTH_NORTH = "SOUTH NORTH"; public static final String NORTH_SOUTH = "NORTH SOUTH"; //테스트 코드 public static final String NORTH = "NORTH"; public static final String SOUTH = "SOUTH"; public static final String WEST = "WEST"; public static final String EAST = "EAST";
-
-
테스트 5 - 배열이 {NORTH, SOUTH, EAST, WEST} 이면 empty 배열을 리턴
-
테스트 코드
@Test @DisplayName("test should return {} when input array {NORTH, SOUTH, EAST, WEST}") public void test6() { // Given: Set array {NORTH, SOUTH, EAST, WEST} String[] given = new String[]{"NORTH", "SOUTH", "EAST", "WEST"}; // Then: Should return empty array assertArrayEquals(new String[]{}, DirReduction.dirReduc(given)); }
-
실제 코드
public class DirReduction { public static final String SOUTH_NORTH = "SOUTH NORTH"; public static final String NORTH_SOUTH = "NORTH SOUTH"; public static final String WEST_EAST = "WEST EAST"; public static final String EAST_WEST = "EAST WEST"; public static String[] dirReduc(String[] arr) { String toString = String.join(" ", arr); toString = toString.replace(SOUTH_NORTH, "") .replace(NORTH_SOUTH, "") .replace(WEST_EAST, "") .replace(EAST_WEST, "").trim(); if (toString.length() == 0) { return new String[]{}; } return toString.split(" "); } }
- 이러고 제출했는데 실패했다. 그 이유가..
-
-
테스트 6 - 배열이 {NORTH, EAST, WEST, SOUTH} 이면 empty 배열을 리턴
-
테스트 코드
@Test @DisplayName("test should return {} when input array {NORTH, EAST, WEST, SOUTH}") public void test7() { // Given: Set array {NORTH, EAST, WEST, SOUTH} String[] given = new String[]{NORTH, EAST, WEST, SOUTH}; // Then: Should return empty array assertArrayEquals(new String[]{}, DirReduction.dirReduc(given)); }
-
실제 코드
public class DirReduction { public static final String SOUTH_NORTH = "SOUTH NORTH"; public static final String NORTH_SOUTH = "NORTH SOUTH"; public static final String WEST_EAST = "WEST EAST"; public static final String EAST_WEST = "EAST WEST"; public static String[] dirReduc(String[] arr) { String toString = String.join(" ", arr); toString = toString.replace(SOUTH_NORTH, "") .replace(NORTH_SOUTH, "") .replace(WEST_EAST, "") .replace(EAST_WEST, "") .replaceAll(" +", " ").trim(); toString = toString.replace(SOUTH_NORTH, "") .replace(NORTH_SOUTH, "") .replace(WEST_EAST, "") .replace(EAST_WEST, "") .replaceAll(" +", " ").trim(); if (toString.length() == 0) { return new String[]{}; } return toString.split(" "); } }
- 이전 구현을 보면 NORTH_SOUTH, SOUTH_NORTH 부터 삭제한다. 테스트 케이스를 보면 NORTH와 SOUTH는 떨어져있는데, EAST WEST를 삭제하면 다시 붙게된다. 그러면 다시 NORTH SOUTH를 삭제해야한다. 그래서 삭제하는 코드를 한번 더 붙였다.
- 그리고 EAST WEST를 삭제하면 NORTH SOUTH로 공백이 2번있다. 그래서 String에서 공백 2개이상을 한개로 바꿔주어야한다. 그래서
replaceAll(" +", " ")
을 사용했다.
-
리팩토링 - 반복문 사용
public class DirReduction { public static final String SOUTH_NORTH = "SOUTH NORTH"; public static final String NORTH_SOUTH = "NORTH SOUTH"; public static final String WEST_EAST = "WEST EAST"; public static final String EAST_WEST = "EAST WEST"; public static String[] dirReduc(String[] arr) { String beforeString = ""; String afterString = String.join(" ", arr); while (beforeString.length() != afterString.length()) { beforeString = afterString; afterString = beforeString.replace(SOUTH_NORTH, "") .replace(NORTH_SOUTH, "") .replace(WEST_EAST, "") .replace(EAST_WEST, "") .replaceAll(" +", " ").trim(); } if (afterString.length() == 0) { return new String[]{}; } return afterString.split(" "); } }
- 반복문을 이용하여 문자열 삭제 전과 후의 길이가 같아질 때까지 반복한다.
-
-
if / else if문, switch문 생각 👉
String.replace()
생각 하는데 시간을 많이 사용했고, 공백 2개 이상을 하나로 줄이는 방법을 생각하는데 또 시간을 많이 사용했다. (약 40분)
2. 답 비교, 느낀점
Best Practice 가장 많이 받은 코드
import java.util.Stack;
public class DirReduction {
public static String[] dirReduc(String[] arr) {
final Stack<String> stack = new Stack<>();
for (final String direction : arr) {
final String lastElement = stack.size() > 0 ? stack.lastElement() : null;
switch(direction) {
case "NORTH": if ("SOUTH".equals(lastElement)) { stack.pop(); } else { stack.push(direction); } break;
case "SOUTH": if ("NORTH".equals(lastElement)) { stack.pop(); } else { stack.push(direction); } break;
case "EAST": if ("WEST".equals(lastElement)) { stack.pop(); } else { stack.push(direction); } break;
case "WEST": if ("EAST".equals(lastElement)) { stack.pop(); } else { stack.push(direction); } break;
}
}
return stack.stream().toArray(String[]::new);
}
}
- Best Practice를 보니 switch문을 사용하긴 했지만, 문제 의도가 stack을 이용하여 해결하는 문제라는것을 알 수 있었다.. 이런 생각을 못한게 너무 아쉽다. 흑흑
댓글남기기