import java.util.ArrayList;
class Solution {
public int[] solution(int[] answers) {
int[] person1 = {1, 2, 3, 4, 5};
int[] person2 = {2, 1, 2, 3, 2, 4, 2, 5};
int[] person3 = {3, 3, 1, 1, 2, 2, 4, 4, 5, 5};
int[] correctValue = {0, 0, 0};
// %연산자를 활용하여 각 수포자별 정답 개수 갱신
for (int i = 0; i < answers.length; i++) {
if(answers[i] == person1[i % person1.length]){
correctValue[0]++;
}
if(answers[i] == person2[i % person2.length]){
correctValue[1]++;
}
if(answers[i] == person3[i % person3.length]){
correctValue[2]++;
}
}
// 수포자 중 가장 큰 정답 개수 구하기
int maxValue = -1;
for (int i = 0; i < 3; i++) {
if(maxValue < correctValue[i]) maxValue = correctValue[i];
}
// list로 점수가 가장 높은 수포자 넣기
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
if(maxValue == correctValue[i]){
list.add(i+1);
}
}
// 이후, 배열로 바꾸어 리턴
int[] answer = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
answer[i] = list.get(i);
}
return answer;
}
}
SpringBoot가 스캔을 해서 등록한 Bean을 Test에서 쓸 수 있게 해줌
아래 코드와 같은 기능
@ExtendsWith
@ConfiguraionContext
ApplicationContext = Spring 에 등록된 빈을 '이름'에 맞게 DI를 해줌
즉, = new ReadlineContext() ~~~ 에서 new를 안하게 해줌
(Singletone : 객체 한번 생성 -> 계속 객체를 생성하지 않도록)
(여러명(ex 10,000명) 1만번의 GC가 돌 수 있기 때문에 Singletone으로 띄움)
Autowired는 주로 Test에서 쓰는 추세
(서비스 코드는 final과 Constructor를 씁니다. 이렇게 해도 Spring이 DI를 해줌)
Column 타입을 세분화하는 이유
DB에 저장공간을 줄이고, 검색 속도를 최적화하기 위함

🟢 datetime으로 설정한 이유
👉 사용빈도가 datetime > date임
이번 경우에는 인허가일자에 date를 해도 괜찮음
(이것만 date 형식이므로)
단, date, datetime 형식이 섞여있으면 datetime으로 통일하여 사용
CREATE TABLE `likelion-db`.`nationwide_hospitals` (
`id` INT NOT NULL,
`open_service_name` VARCHAR(10) NULL COMMENT '개방서비스명',
`open_local_government_code` INT NOT NULL COMMENT '개방자치단체코드',
`management_number` VARCHAR(40) NULL COMMENT '관리번호',
`license_date` DATETIME NULL COMMENT '인허가일자',
`business_status` TINYINT(2) NULL COMMENT '영업상태명',
`business_status_code` TINYINT(2) NULL COMMENT '상세영업상태코드',
`phone` VARCHAR(20) NULL COMMENT '소재지전화',
`full_address` VARCHAR(200) NULL COMMENT '소재지전체주소',
`road_name_address` VARCHAR(200) NULL COMMENT '도로명전체주소',
`hospital_name` VARCHAR(20) NULL COMMENT '사업장명',
`business_type_name` VARCHAR(10) NULL COMMENT '업태구분명',
`healthcare_provider_count` TINYINT(3) NULL COMMENT '의료인수',
`patient_room_count` TINYINT(3) NULL COMMENT '입원실수',
`total_number_of_beds` TINYINT(3) NULL COMMENT '병상수',
`total_area_size` FLOAT NULL COMMENT '총면적',
PRIMARY KEY (`id`),
UNIQUE INDEX `management_number_UNIQUE` (`management_number` ASC) VISIBLE);
import java.time.LocalDateTime;
@AllArgsConstructor // 모든 변수를 가진 생성자
@Getter // Getter
@Setter // Setter
@NoArgsConstructor // 기본생성자
public class Hospital {
private int id;
private String OpenServiceName;
private int openLocalGovernmentCode;
private String managementNumber;
private LocalDateTime licenseDate;
private int businessStatus;
private int businessStatusCode;
private String phone;
private String fullAddress;
private String roadNameAddress;
private String hospitalName;
private String businessTypeName;
private int healthcareProviderCount;
private int patientRoomCount;
private int totalNumberOfBeds;
private float totalAreaSize;
}
public interface Parser<T> {
T parse(String str);
}
import com.springboot.springbootcoreguide.domain.Hospital;
import java.time.LocalDateTime;
public class HospitalParser implements Parser<Hospital> {
@Override
public Hospital parse(String str) {
String[] row = str.split("\",\"");
Hospital hospital = new Hospital();
hospital.setId(Integer.parseInt(row[0].replace("\"", "")));
hospital.setOpenServiceName(row[1]);
hospital.setOpenLocalGovernmentCode(Integer.parseInt(row[3]));
hospital.setManagementNumber(row[4]);
int year = Integer.parseInt(row[5].substring(0, 4));
int month = Integer.parseInt(row[5].substring(4, 6));
int day = Integer.parseInt(row[5].substring(6));
hospital.setLicenseDate(LocalDateTime.of(year, month, day, 0, 0, 0));
hospital.setBusinessStatus(Integer.parseInt(row[7]));
hospital.setBusinessStatusCode(Integer.parseInt(row[9]));
hospital.setPhone(row[15]);
hospital.setFullAddress(row[18]);
hospital.setRoadNameAddress(row[19]);
hospital.setHospitalName(row[21]);
hospital.setBusinessTypeName(row[25]);
hospital.setHealthcareProviderCount(Integer.parseInt(row[29]));
hospital.setPatientRoomCount(Integer.parseInt(row[30]));
hospital.setTotalNumberOfBeds(Integer.parseInt(row[31]));
hospital.setTotalAreaSize(Float.parseFloat(row[32].replace("\"", "")));
return hospital;
}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ReadLineContext<T> {
private Parser<T> parser;
public ReadLineContext(Parser<T> parser) {
this.parser = parser;
}
public List<T> readByLine(String filename) throws IOException {
// 삽
List<T> result = new ArrayList<>();
BufferedReader reader = new BufferedReader(
new FileReader(filename)
);
String str;
while ((str = reader.readLine()) != null) {
try {
result.add(parser.parse(str));
} catch (Exception e) {
System.out.printf("파싱 중 문제가 생겨 이 라인은 넘어갑니다. 파일내용:%s\n", str);
}
}
reader.close();
return result;
}
}
import com.springboot.springbootcoreguide.domain.Hospital;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ParserFactory {
@Bean
public ReadLineContext<Hospital> hospitalReadLineContext() {
return new ReadLineContext<Hospital>(new HospitalParser());
}
}
import com.springboot.springbootcoreguide.domain.Hospital;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class HospitalParserTest {
String line1 = "\"1\",\"의원\",\"01_01_02_P\",\"3620000\",\"PHMA119993620020041100004\",\"19990612\",\"\",\"01\",\"영업/정상\",\"13\",\"영업중\",\"\",\"\",\"\",\"\",\"062-515-2875\",\"\",\"500881\",\"광주광역시 북구 풍향동 565번지 4호 3층\",\"광주광역시 북구 동문대로 24, 3층 (풍향동)\",\"61205\",\"효치과의원\",\"20211115113642\",\"U\",\"2021-11-17 02:40:00.0\",\"치과의원\",\"192630.735112\",\"185314.617632\",\"치과의원\",\"1\",\"0\",\"0\",\"52.29\",\"401\",\"치과\",\"\",\"\",\"\",\"0\",\"0\",\"\",\"\",\"0\",\"\",";
@Autowired
ReadLineContext<Hospital> hospitalReadLineContext;
@Test
@DisplayName("10만 건 이상 데이터가 파싱되는지")
void OneHundreadThousandRows() throws IOException {
String filename = "D:\\고관운 자료\\멋쟁이사자처럼\\수업 자료\\fulldata_01_01_02_P_의원_utf8.csv";
List<Hospital> hospitalList = hospitalReadLineContext.readByLine(filename);
assertTrue(hospitalList.size() > 100000);
for (int i = 0; i < 10; i++) {
System.out.println(hospitalList.get(i).getHospitalName());
}
}
@Test
@DisplayName("csv 1줄을 Hospital로 잘 만드는지 Test")
void convertToHospital() {
HospitalParser hp = new HospitalParser();
Hospital hospital = hp.parse(line1);
assertEquals(1, hospital.getId());
assertEquals("의원", hospital.getOpenServiceName());
assertEquals(3620000, hospital.getOpenLocalGovernmentCode());
assertEquals("PHMA119993620020041100004", hospital.getManagementNumber());
assertEquals(LocalDateTime.of(1999, 6, 12, 0, 0, 0), hospital.getLicenseDate());
assertEquals(1, hospital.getBusinessStatus());
assertEquals(13, hospital.getBusinessStatusCode());
assertEquals("062-515-2875", hospital.getPhone());
assertEquals("광주광역시 북구 풍향동 565번지 4호 3층", hospital.getFullAddress());
assertEquals("광주광역시 북구 동문대로 24, 3층 (풍향동)", hospital.getRoadNameAddress());
assertEquals("효치과의원", hospital.getHospitalName());
assertEquals("치과의원", hospital.getBusinessTypeName());
assertEquals(1, hospital.getHealthcareProviderCount());
assertEquals(0, hospital.getPatientRoomCount());
assertEquals(0, hospital.getTotalNumberOfBeds());
assertEquals(52.29f, hospital.getTotalAreaSize());
}
}
🔴 4번 과정을 겪으면서 어려웠던 점
,가 있었기 때문에 ,로 split을 하지 못함","으로 split한 후, 0과 마지막 인덱스의 값에 "제거🔴 데이터 오류 처리 방법