Codewars 문제풀기 (04/09)
Two to One
- String 2개를 인수로 받는다.
- 두 String을 합친 String을 반환한다.
- 단, 합친 String에 중복된 문자는 없어야하며, 알파벳순서로 출력된다.
- longest(“aretheyhere”, “yestheyarehere”) –> “aehrsty”
- longest(“xyaabbbccccdefww”, “xxxxyyyyabklmopq”) –> “abcdefklmopqwxy”
- longest(“abcdefghijklmnopqrstuvwxyz”, “abcdefghijklmnopqrstuvwxyz”) –> “abcdefghijklmnopqrstuvwxyz”
1. Test와 리팩토링
-
처음에 테스트 짜는것을 고민했다. 입력 문자열이 같을경우 그대로 입력문자열 그대로 반환하되 문자열은 알파벳 순서이고, 중복문자는 없어야한다.
-
테스트 코드
@Test public void testShouldReturnAlphabetSortedStringWhenInputTwoStringIsSame() { // Given: Set input same string String given1 = "bacedfghikjlmnopqrstuvwxyz"; String given2 = "bacedfghikjlmnopqrstuvwxyz"; // When: Call twoToOne method String actual = TwoToOne.longest(given1, given2); // Then: Should return alphabet sort "abcdefghijklmnopqrstuvwxyz" assertEquals("abcdefghijklmnopqrstuvwxyz", actual); }
-
실제 코드
import java.util.Arrays; public class TwoToOne { public static String longest(String s1, String s2) { String result = String.join("", s1, s2); char[] toCharArray = result.toCharArray(); for (int i = 0; i < toCharArray.length; i++) { for (int j = 0; j < i; j++) { if (toCharArray[i] == toCharArray[j]) { toCharArray[j] = ' '; } } } Arrays.sort(toCharArray); return String.valueOf(toCharArray).trim(); } }
-
처음에 두 입력 문자열을 stream에 넣은 후 같은 문자를 삭제하는 최종연산 메서드를 사용하면 되지않을까? 생각했었는데, 그 방법을 잘 모르겠어서 char 배열로 만든 후 같은 문자가 있으면 ‘ ‘(space)로 바꾼 후 반환할때 trim()메서드로 공백을 삭제하는 방법으로 해결했다.
-
-
이렇게 하고 나니까 다른 모든 테스트에도 먹히는거 같은데? 라는 생각으로 문제에 있는 테스트 예제를 입력해보았다.
-
테스트 코드
@Test public void testShouldDeleteDuplicateCharacters() { // Given: Set input different string String given1 = "aretheyhere"; String given2 = "yestheyarehere"; // When: Call twoToOne method String actual = TwoToOne.longest(given1, given2); // Then: Should return alphabet sort "aehrsty" assertEquals("aehrsty", actual); }
-
실제 코드 바뀐거 없이 그대로 테스트 케이스를 실행해보니 잘 돌아갔다. 그래서 일단 제출했다.
-
-
리팩토링
-
join()메서드를 호출하여 지역변수에 저장할 필요없이 바로 char 배열을 사용해도 될 것 같다.
import java.util.Arrays; public class TwoToOne { public static String longest(String s1, String s2) { char[] result = String.join("", s1, s2).toCharArray(); for (int i = 0; i < result.length; i++) { for (int j = 0; j < i; j++) { if (result[i] == result[j]) { result[j] = ' '; } } } Arrays.sort(result); return String.valueOf(result).trim(); } }
- String result 지역변수를 삭제하고, char[] 이름 toCharArray를 result로 바꿨다.
- 2중 for문을 사용한것이 마음에 들진 않았지만 더 좋은방법이 생각이 안나서 그냥 제출했다. (리팩토링 제외 약 15분 - stream으로 해결하려고 생각하다가 방법을 몰라서 2중 for문 사용)
-
2. 답 비교, 느낀점
Best Practice 가장 많이 받은 코드
public class TwoToOne {
public static String longest (String s1, String s2) {
String s = s1 + s2;
return s.chars().distinct().sorted().collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
}
}
- distinct()가 스트림에서 중복 아이템을 제거하는 메서드라는 것을 알 수 있다.
-
그런데 뒤의 collect()메서드에서 사용되는 StringBuilder..부분을 잘 모르겠다.
- 나는 join()메서드를 사용했는데 굳이 그럴필요 없이 concat()메서드나 +연산을 사용해도 되겠구나 생각이 들었다.
그외 감명(?)받은 답변들
public class TwoToOne {
public static String longest(String s1, String s2) {
String out = "";
String s = s1 + s2;
for (char c = 'a'; c <= 'z'; c++) {
if (s.contains(c + "")) {
out += c;
}
}
return out;
}
}
- 뭐 굳이 스트림 사용하지않아도 for문 하나로 처리할 수 있다.
import java.util.stream.*;
public class TwoToOne {
public static String longest (String s1, String s2) {
return Stream.of(s1.concat(s2).split(""))
.sorted()
.distinct()
.collect(Collectors.joining());
}
}
- 내가 스트림을 사용했다면 이렇게 푸는게 가장 내가 이해하기 쉬운 답변이다.
3. 알게된 것
- distinct() –> 스트림의 중복 아이템들을 삭제한다.
4. 모르는것
- collect의 인자로 String :: , StringBuilder::등을 사용했는데 뭔지 잘 모르겠다.
댓글남기기