1. 문제
music : mp3, aac, flac
image : jpg, bmp, gif
movie : mp4, aiv, mkv
other : 7z, txt, zip
위와 같은 파일 확장자가 존재 하고, music, image, movie, other 그룹으로 분리 할수 있다.
input :
"my.song.mp3 11b
greatSong.flac 1000b
not3.txt 5b
video.mp4 200b
game.exe 100b
mov!e.mkv 10000b"
위와 같은 input 이 주어 졌을 때, 아래와 같은 반환 값이 출력 되도록 solution 함수를 구현 하시오.
return :
"music 1011b
images 0b
movies 10200b
other 105b
"
파일이름, 확장자, 파일 크기 의 규칙은 아래와 같습니다.
파일 이름
1. 영어 대/소문자 만 허용
2. 특수문자 : ^&'@{}[],$=!-#()%.+~_ 만 허용
3. 숫자 (0 ~ 9)
확장자
1. 영어 소문자
2. 숫자 (0 ~ 9)
파일 크기
1. 양수 ~ 1,000,000b(백만 바이트)
2. 접근
1. 띄어쓰기를 기준으로, 파일이름과 크기를 분리
2, 파일 이름 중에서 끝에서 부터 탐색하여 (. dot) 을 찾아내고
3. dot 뒤의 문자열을 파일 타입으로 정의
4. 4가지 타입 중 하나로 분류
5. 해당 라인의 용량을 저장
6. 출력 포맷의 맞게 출력
위와 같이, 알고리즘 구현 접근을 하였습니다. 오늘 글 포스팅은 기능 확장 및 수정의 초점을 맞춰서 포스팅 하려고 합니다.
3. 1차 Java 소스 코드
import java.util.ArrayList;
import java.util.List;
public class Task2020_2 {
public static void main(String[] args) {
String input = "my.song.mp3 11b\n" +
"greatSong.flac 1000b\n" +
"not3.txt 5b\n" +
"video.mp4 200b\n" +
"game.exe 100b\n" +
"mov!e.mkv 10000b";
System.out.print(new Task2020_2().solution(input));
}
FileSizeGroup fileSizeGroup;
public String solution(String S) {
// 4. 4가지 타입 중 하나로 분류
this.fileSizeGroup = new FileSizeGroup();
// 각 라인을 분리
String[] rows = S.split("\n");
for (String row : rows) {
// 1. 띄어쓰기를 기준으로, 파일이름과 크기를 분리
String fileFullName = row.split(" ")[0];
String sizeStr = row.split(" ")[1];
int size = Integer.parseInt(sizeStr.substring(0, sizeStr.length() - 1));
// 2. 파일 이름 중에서 끝에서 부터 탐색하여 (.(dot))을 찾아내고
// 3. dot 뒤의 문자열을 파일 타입으로 정의
for (int i = fileFullName.length() - 1; i >= 0; i--) {
if (fileFullName.charAt(i) == '.') {
String fileType = fileFullName.substring(i + 1);
// 4. 4가지 타입 중 하나로 분류
insertFileSizeToFileGroup(fileType, size);
break;
}
}
}
StringBuilder sb = new StringBuilder();
// 5. 해당 라인의 용량을 저장
for (FileType value : FileType.values()) {
String type = value.name;
int size = fileSizeGroup.getSumSize(value);
// 6. 출력 포맷의 맞게 출력
sb.append(type).append(" ").append(size).append("b");
sb.append(System.lineSeparator());
}
return sb.toString();
}
public void insertFileSizeToFileGroup(String fileType, int size) {
switch (fileType) {
//music
case "mp3" :
case "aac" :
case "flac" : {
this.fileSizeGroup.musicSizes.add(size);
return;
}
//image
case "jpg" :
case "bmp" :
case "gif" : {
this.fileSizeGroup.imageSizes.add(size);
return;
}
//movie
case "mp4" :
case "avi" :
case "mkv" : {
this.fileSizeGroup.movieSizes.add(size);
return;
}
//other
default : {
this.fileSizeGroup.otherSizes.add(size);
return;
}
}
}
class FileSizeGroup {
List<Integer> musicSizes;
List<Integer> imageSizes;
List<Integer> movieSizes;
List<Integer> otherSizes;
public FileSizeGroup() {
this.musicSizes = new ArrayList<>();
this.imageSizes = new ArrayList<>();
this.movieSizes = new ArrayList<>();
this.otherSizes = new ArrayList<>();
}
int getSumSize(FileType fileType){
int sum = 0;
if (fileType == FileType.MUSIC)
sum = getSumFrom(musicSizes);
if (fileType == FileType.IMAGE)
sum = getSumFrom(imageSizes);
if (fileType == FileType.MOVIE)
sum = getSumFrom(imageSizes);
if (fileType == FileType.OTHER)
sum = getSumFrom(otherSizes);
return sum;
}
private int getSumFrom(List<Integer> list) {
int sum = 0;
for (Integer val : list) {
sum += val;
}
return sum;
}
}
enum FileType {
MUSIC("music"), IMAGE("images"),
MOVIE("movies"), OTHER("other");
String name;
FileType(String name) {
this.name = name;
}
}
}
여기서 눈여겨 볼것은 insertFileSizeToFileGroup() 함수와 FileSizeGroup 클래스 입니다. insertFileSizeToFileGroup 함수에서는 파일 타입 그룹별로 switch 문을 이용해서 그룹별로 size를 저장 합니다. 그리고 해당 그룹의 파일 size 를 출력 하기 위해서는 FileSizeGroup.getSumSize()에서 그룹별로 저장해둔 size를 더해서 반환해 줍니다.
만약, 'text' 라는 그룹의 'txt' 확장자가 추가 된다면, 위 소스에서 어디를 수정해 주어야 할까요?
1. FileType enum
enum FileType {
MUSIC("music"), IMAGE("images"),
MOVIE("movies"), TEXT("text"),
OTHER("other");
String name;
FileType(String name) {
this.name = name;
}
}
'TEXT' 라는 파일 타입 그룹을 추가 시켜주면 됩니다.
2. FileSizeGroup class
class FileSizeGroup {
List<Integer> musicSizes;
List<Integer> imageSizes;
List<Integer> movieSizes;
List<Integer> textSizes;
List<Integer> otherSizes;
public FileSizeGroup() {
this.musicSizes = new ArrayList<>();
this.imageSizes = new ArrayList<>();
this.movieSizes = new ArrayList<>();
this.textSizes = new ArrayList<>();
this.otherSizes = new ArrayList<>();
}
int getSumSize(FileType fileType){
int sum = 0;
if (fileType == FileType.MUSIC)
sum = getSumFrom(musicSizes);
if (fileType == FileType.IMAGE)
sum = getSumFrom(imageSizes);
if (fileType == FileType.MOVIE)
sum = getSumFrom(imageSizes);
if (fileType == FileType.TEXT)
sum = getSumFrom(textSizes);
if (fileType == FileType.OTHER)
sum = getSumFrom(otherSizes);
return sum;
}
...
}
'TEXT' 라는 파일 타입 그룹이 추가 될수록 getSumSize 함수의 if 문은 추가 될것 입니다. 또한 List<Integer> textSizes 변수도 추가 될것 입니다.
3. insertFileSizeToFileGroup 함수
public void insertFileSizeToFileGroup(String fileType, int size) {
switch (fileType) {
//music
case "mp3" :
case "aac" :
case "flac" : {
this.fileSizeGroup.musicSizes.add(size);
return;
}
//image
case "jpg" :
case "bmp" :
case "gif" : {
this.fileSizeGroup.imageSizes.add(size);
return;
}
//movie
case "mp4" :
case "avi" :
case "mkv" : {
this.fileSizeGroup.movieSizes.add(size);
return;
}
//movie
case "txt" : {
this.fileSizeGroup.textSizes.add(size);
return;
}
//other
default : {
this.fileSizeGroup.otherSizes.add(size);
return;
}
}
}
'txt' 파일 확장자가 추가되면 switch 문의 case는 추가 될것 입니다. insertFileSizeToFileGroup 함수는 Task2020_2 클래스의 메서드로 정의 되어 있지만, 'txt', 'mp3' 등 파일 확장자의 데이터를 굳이 가지고 있을 필요가 없고, FileType enum 에서 관리를 해주도록 수정 할수 있을거 같습니다.
따라서, 파일 확장자 추가 및 파일 그룹 추가시 확장의 용이 하도록 아래와 같이 수정 하였습니다.
4. 2차 Java 소스 코드
import java.util.*;
public class Task2020_2_2 {
public static void main(String[] args) {
String input = "my.song.mp3 11b\n" +
"greatSong.flac 1000b\n" +
"not3.txt 5b\n" +
"video.mp4 200b\n" +
"game.exe 100b\n" +
"mov!e.mkv 10000b";
System.out.print(new Task2020_2_2().solution(input));
}
public String solution(String S) {
// 각 라인을 분리
String[] rows = S.split("\n");
for (String row : rows) {
// 1. 띄어쓰기를 기준으로, 파일이름과 크기를 분리
String fileFullName = row.split(" ")[0];
String sizeStr = row.split(" ")[1];
int size = Integer.parseInt(sizeStr.substring(0, sizeStr.length() - 1));
// 2. 파일 이름 중에서 끝에서 부터 탐색하여 (.(dot))을 찾아내고
// 3. dot 뒤의 문자열을 파일 타입으로 정의
for (int i = fileFullName.length() - 1; i >= 0; i--) {
if (fileFullName.charAt(i) == '.') {
String fileTypeStr = fileFullName.substring(i + 1);
// 4. 4가지 타입 중 하나로 분류
FileType fileType = FileType.convertStrToFileType(fileTypeStr);
FileTypeGroup fileTypeGroup = FileTypeGroup.findByFileType(fileType);
fileTypeGroup.addSize(size);
break;
}
}
}
StringBuilder sb = new StringBuilder();
// 5. 해당 라인의 용량을 저장
for (FileTypeGroup value : FileTypeGroup.values()) {
String type = value.title;
int size = value.getTotal();
// 6. 출력 포맷의 맞게 출력
sb.append(type).append(" ").append(size).append("b");
sb.append(System.lineSeparator());
}
return sb.toString();
}
enum FileTypeGroup {
MUSIC("music", Arrays.asList(FileType.MP3, FileType.AAC, FileType.FLAC)),
IMAGE("images", Arrays.asList(FileType.JPG, FileType.BMP, FileType.GIF)),
MOVIE("movies", Arrays.asList(FileType.MP4, FileType.AVI, FileType.MKV)),
OTHER("other", Arrays.asList(FileType.OTHER));
String title;
List<FileType> fileTypes;
int total;
FileTypeGroup(String title, List<FileType> fileTypes) {
this.title = title;
this.fileTypes = fileTypes;
}
void addSize(int size) {
this.total += size;
}
int getTotal() {
return total;
}
public static FileTypeGroup findByFileType(FileType fileType){
return Arrays.stream(FileTypeGroup.values())
.filter(FileTypeGroup -> FileTypeGroup.hasFileType(fileType))
.findAny()
.orElse(OTHER);
}
public boolean hasFileType(FileType fileType) {
return fileTypes.stream()
.anyMatch(elem -> elem == fileType);
}
}
enum FileType {
MP3("mp3"), AAC("aac"), FLAC("flac"),
JPG("jpg"), BMP("bmp"), GIF("gif"),
MP4("mp4"), AVI("avi"), MKV("mkv"),
OTHER("other");
String title;
FileType(String title) {
this.title = title;
}
public static FileType convertStrToFileType(String title) {
return Arrays.stream(FileType.values())
.filter(elem -> elem.title.equals(title))
.findAny()
.orElse(OTHER);
}
}
}
Task2020_2 클래스의 insertFileSizeToFileGroup 함수가 사라지고, FileType 과 관련된 데이터가 사라지므로써, FileType의 의존하지 않습니다. FileTypeGroup 의 고수준 클래스는 FileType 의 저수준 클래스에도 의존하지 않고, TEXT 의 정의만 추가해 줄 수 있습니다.
그렇다면, 이 소스 코드에서 TEXT 그룹과 'txt' 확장자 추가시 아래의 소스 코드 처럼 수정 할수 있을거 같습니다.
1. FileType enum의 TXT enum 추가
enum FileType {
MP3("mp3"), AAC("aac"), FLAC("flac"),
JPG("jpg"), BMP("bmp"), GIF("gif"),
MP4("mp4"), AVI("avi"), MKV("mkv"),
TXT("txt"),
OTHER("other");
String title;
FileType(String title) {
this.title = title;
}
public static FileType convertStrToFileType(String title) {
return Arrays.stream(FileType.values())
.filter(elem -> elem.title.equals(title))
.findAny()
.orElse(OTHER);
}
}
TXT("txt") 정의만 해주면 됩니다.
2. FileTypeGroup enum의 TEXT enum추가
enum FileTypeGroup {
MUSIC("music", Arrays.asList(FileType.MP3, FileType.AAC, FileType.FLAC)),
IMAGE("images", Arrays.asList(FileType.JPG, FileType.BMP, FileType.GIF)),
MOVIE("movies", Arrays.asList(FileType.MP4, FileType.AVI, FileType.MKV)),
TEXT("text", Arrays.asList(FileType.TXT)),
OTHER("other", Arrays.asList(FileType.OTHER));
String title;
List<FileType> fileTypes;
int total;
FileTypeGroup(String title, List<FileType> fileTypes) {
this.title = title;
this.fileTypes = fileTypes;
}
void addSize(int size) {
this.total += size;
}
int getTotal() {
return total;
}
public static FileTypeGroup findByFileType(FileType fileType){
return Arrays.stream(FileTypeGroup.values())
.filter(FileTypeGroup -> FileTypeGroup.hasFileType(fileType))
.findAny()
.orElse(OTHER);
}
public boolean hasFileType(FileType fileType) {
return fileTypes.stream()
.anyMatch(elem -> elem == fileType);
}
}
FileTypeGroup 의 TEXT("text", Arrays.asList(FileType.TXT)) 정의 만 추가해 주었습니다.
'Algorithm' 카테고리의 다른 글
곱하기 혹은 더하기 - 페이스북 기출 유형 (0) | 2020.09.22 |
---|---|
공유기 설치 - 백준 2110번 (0) | 2020.09.22 |
국영수 - '백준 10825번' (0) | 2020.09.18 |
기둥과 보 설치 - '2020 카카오 코딩 테스트' (0) | 2020.09.15 |
외벽 점검 - '카카오 2020 코딩 테스트' (0) | 2020.09.12 |