Codewars 문제풀기 (05/19)
Human readable duration format
-
int를 입력으로 받는다.
-
정수를 time format으로 변경하여 String으로 리턴한다.
-
year, day, hour, minute, second으로 표현한다.
TimeFormatter.formatDuration(1) 👉 1 second TimeFormatter.formatDuration(62) 👉 1 minute and 2 seconds TimeFormatter.formatDuration(3722) 👉 1 hour, 2 minutes and 2 seconds TimeFormatter.formatDuration(7202) 👉 2 hours and 2 seconds
1. Test와 리팩토링
-
테스트 1 - 입력이 1이면 “1 second”를 리턴한다.
-
@Test @DisplayName("test should return 1 second when input 1") public void test1() { // Then: Should return 1 second assertEquals("1 second", TimeFormatter.formatDuration(1)); }
-
public class TimeFormatter { public static String formatDuration(int seconds) { return seconds + " second"; } }
-
-
테스트 2 - 입력이 62이면 “1 minute and 2 seconds”를 리턴한다.
-
@Test @DisplayName("test should return 1 minute and 2 seconds second when input 62") public void test2() { // Then: Should return 1 minute and 2 seconds assertEquals("1 minute and 2 seconds", TimeFormatter.formatDuration(62)); }
-
public class TimeFormatter { public static String formatDuration(int seconds) { String result = ""; if (seconds >= 60) { if (seconds / 60 > 1) { result = seconds / 60 + " minutes and "; } else { result = seconds / 60 + " minute and "; } } if (seconds % 60 > 1) { result = result + seconds % 60 + " seconds"; } else { result = result + seconds % 60 + " second"; } return result; } }
- 값이 1보다 크면 format에 s를 붙여줘야하기 때문에 if문으로 처리했다.
-
public class TimeFormatter { public static String formatDuration(int seconds) { String result = ""; int second = seconds % 60; int minute = seconds / 60; if (minute > 0) { result = minute + (minute > 1 ? " minutes and " : " minute and "); } result += second + (second > 1 ? " seconds" : " second"); return result; } }
- 3항 연산자로 더 짧게 처리했다.
-
-
테스트 3 - 입력이 60이면 “2 minutes”를 리턴한다.
-
@Test @DisplayName("test should return 2 minutes when input 120") public void test3() { // Then: Should return 2 minutes assertEquals("2 minutes", TimeFormatter.formatDuration(120)); }
-
public class TimeFormatter { public static String formatDuration(int seconds) { String result = ""; int second = seconds % 60; int minute = seconds / 60; if (second > 0) { result = second + (second > 1 ? " seconds" : " second"); } if (minute > 0) { if (second > 0) { result = " and " + result; } result = minute + (minute > 1 ? " minutes" : " minute") + result; } return result; } }
- “2 minutes” 이후에 second가 없으면 “and”를 붙이면 안된다. 그래서 second가 0보다 클 때만 “and”를 붙이도록 했다.
-
-
테스트 4 - 입력이 3600이면 “1 hour”를 리턴한다.
-
@Test @DisplayName("test should return 1 hour when input 3600") public void test4() { // Then: Should return 1 hour assertEquals("1 hour", TimeFormatter.formatDuration(3600)); }
-
public class TimeFormatter { public static String formatDuration(int seconds) { String result = ""; int hour = seconds / 3600; int minute = seconds % 3600 / 60; int second = seconds % 60; if (second > 0) { result = second + (second > 1 ? " seconds" : " second"); } if (minute > 0) { if (second > 0) { result = " and " + result; } result = minute + (minute > 1 ? " minutes" : " minute") + result; } if (hour > 0) { if (minute > 0 || second > 0) { result = " and" + result; } result = hour + (hour > 1 ? " hours" : " hour") + result; } return result; } }
- 이 test만 봤을 때 “1 hour”가 리턴되도록 구현했다.
-
-
테스트 5 - 입력이 3662일때 “1 hour, 1 minute and 2 seconds”를 리턴한다.
-
@Test @DisplayName("test should return 1 hour, 1 minute and 2 seconds when input 3662") public void test5() { // Then: Should return 1 hour, 1 minute and 2 seconds assertEquals("1 hour, 1 minute and 2 seconds", TimeFormatter.formatDuration(3662)); }
-
public class TimeFormatter { public static String formatDuration(int seconds) { String result = ""; int hour = seconds / 3600; int minute = seconds % 3600 / 60; int second = seconds % 60; if (second > 0) { result = second + (second > 1 ? " seconds" : " second"); } if (minute > 0) { if (second > 0) { result = " and " + result; } result = minute + (minute > 1 ? " minutes" : " minute") + result; } if (hour > 0) { if (minute > 0 || second > 0) { result = ", " + result; } result = hour + (hour > 1 ? " hours" : " hour") + result; } return result; } }
- “and”가 붙는게 아니라 “,”가 붙기 때문에 수정했다.
-
-
테스트 6 - 입력이 15731080이면 “182 days, 1 hour, 44 minutes and 40 seconds”를 리턴한다.
-
@Test @DisplayName("test should return 182 days, 1 hour, 44 minutes and 40 seconds when input 15731080") public void test6() { // Then: Should return 182 days, 1 hour, 44 minutes and 40 seconds assertEquals("182 days, 1 hour, 44 minutes and 40 seconds", TimeFormatter.formatDuration(15731080)); }
-
public class TimeFormatter { public static String formatDuration(int seconds) { String result = ""; int day = seconds / (3600 * 24); int hour = seconds % (3600 * 24) / 3600; int minute = seconds % 3600 / 60; int second = seconds % 60; if (second > 0) { result = second + (second > 1 ? " seconds" : " second"); } if (minute > 0) { if (second > 0) { result = " and " + result; } result = minute + (minute > 1 ? " minutes" : " minute") + result; } if (hour > 0) { if (minute > 0 || second > 0) { result = ", " + result; } result = hour + (hour > 1 ? " hours" : " hour") + result; } if (day > 0) { if (hour > 0 || minute > 0 || second > 0) { result = ", " + result; } result = day + (day > 1 ? " days" : " day") + result; } return result; } }
- 단순히 day의 경우만 추가했다.
-
-
테스트 7 - 입력이 0이면 “now”를 리턴한다.
-
@Test @DisplayName("test should return now when input 0") public void test7() { // Then: Should return now assertEquals("now", TimeFormatter.formatDuration(0)); }
-
public class TimeFormatter { public static String formatDuration(int seconds) { if (seconds == 0) { return "now"; } ... } }
- seconds가 0일 때의 경우를 추가했다.
-
import java.util.ArrayList; import java.util.List; public class TimeFormatter { public static String formatDuration(int seconds) { if (seconds == 0) { return "now"; } String result = ""; List<String> format = new ArrayList<>(); int year = seconds / (3600 * 24 * 365); int day = seconds % (3600 * 24 * 365) / (3600 * 24); int hour = seconds % (3600 * 24) / 3600; int minute = seconds % 3600 / 60; int second = seconds % 60; if (year > 0) { format.add(year + (year > 1 ? " years" : " year")); } if (day > 0) { format.add(day + (day > 1 ? " days" : " day")); } if (hour > 0) { format.add(hour + (hour > 1 ? " hours" : " hour")); } if (minute > 0) { format.add(minute + (minute > 1 ? " minutes" : " minute")); } if (second > 0) { format.add(second + (second > 1 ? " seconds" : " second")); } if (format.size() > 1) { result = String.join(", ", format); String frontComponent = result.substring(0, result.lastIndexOf(",")); String lastComponent = result.substring(result.lastIndexOf(",") + 1); result = frontComponent + " and" + lastComponent; } else { result = String.join("", format); } return result; } }
- 문제를 잘 못 봤다. “years, days, hours, minutes and second” format으로 리턴해야한다. “years and seconds” 이런식으로.. 그래서 생각한 방법이 각 format에 해당하는 값이 1 이상이면 List에 저장한 뒤
String.join()
메서드로 “, “를 붙여서 이어준다. 그리고 마지막 “, “를 “and “로 수정한 뒤 리턴하도록 구현했다.
- 문제를 잘 못 봤다. “years, days, hours, minutes and second” format으로 리턴해야한다. “years and seconds” 이런식으로.. 그래서 생각한 방법이 각 format에 해당하는 값이 1 이상이면 List에 저장한 뒤
-
public class TimeFormatter { private static int SECOND_PER_MINUTE = 60; private static int SECOND_PER_HOUR = 60 * SECOND_PER_MINUTE; private static int SECOND_PER_DAY = 24 * SECOND_PER_HOUR; private static int SECOND_PER_YEAR = 365 * SECOND_PER_DAY; public static String formatDuration(int seconds) { if (seconds == 0) { return "now"; } int year = seconds / SECOND_PER_YEAR; seconds = seconds % SECOND_PER_YEAR; int day = seconds / SECOND_PER_DAY; seconds = seconds % SECOND_PER_DAY; int hour = seconds / SECOND_PER_HOUR; seconds = seconds % SECOND_PER_HOUR; int minute = seconds / SECOND_PER_MINUTE; int second = seconds % SECOND_PER_MINUTE; ... } }
- 매직 넘버를 상수로 변환했다.
-
public class TimeFormatter { private static int SECOND_PER_MINUTE = 60; private static int SECOND_PER_HOUR = 60 * SECOND_PER_MINUTE; private static int SECOND_PER_DAY = 24 * SECOND_PER_HOUR; private static int SECOND_PER_YEAR = 365 * SECOND_PER_DAY; public static String formatDuration(int seconds) { ... List<String> format = new ArrayList<>(); if (year > 0) { format.add(year + (year > 1 ? " years" : " year")); } if (day > 0) { format.add(day + (day > 1 ? " days" : " day")); } if (hour > 0) { format.add(hour + (hour > 1 ? " hours" : " hour")); } if (minute > 0) { format.add(minute + (minute > 1 ? " minutes" : " minute")); } if (second > 0) { format.add(second + (second > 1 ? " seconds" : " second")); } return makeStringFormat(format); } private static String makeStringFormat(List<String> format) { String result = ""; if (format.size() > 1) { result = String.join(", ", format); String frontComponent = result.substring(0, result.lastIndexOf(",")); String lastComponent = result.substring(result.lastIndexOf(",") + 1); result = frontComponent + " and" + lastComponent; } else { result = String.join("", format); } return result; } }
- ”, “를 “and “로 수정하는 부분을 따로 메서드 추출했다.
-
2. 답 비교, 느낀점
Best Practice 가장 많이 받은 코드
import java.util.Arrays;
import java.util.stream.*;
public class TimeFormatter {
public static String formatDuration(int seconds) {
return seconds == 0 ? "now" :
Arrays.stream(
new String[]{
formatTime("year", (seconds / 31536000)),
formatTime("day", (seconds / 86400)%365),
formatTime("hour", (seconds / 3600)%24),
formatTime("minute",(seconds / 60)%60),
formatTime("second",(seconds%3600)%60)})
.filter(e->e!="")
.collect(Collectors.joining(", "))
.replaceAll(", (?!.+,)", " and ");
}
public static String formatTime(String s, int time){
return time==0 ? "" : Integer.toString(time)+ " " + s + (time==1?"" : "s");
}
}
formatTime
이라는 메서드를 만들어서 값이 String 배열에 저장 후 “, “를 붙여주면서 join한다. 그리고 마지막 “, “를 “and “로 바꾸는 것을 정규식을 이용했다.- 처음으로 4Kyu 문제를 풀어봤는데 4Kyu중에 쉬운 문제긴 했지만 시간이 좀 걸렸다.
댓글남기기