-
TIL #5 - 배열프로그래밍/TIL(국비과정) 2020. 3. 31. 20:14
# 2차원 배열 코드
# 학생 5명의 국여수 점수 관리하기
아래의 코드에서는 학생 5명 분의 국영수 점수를 각각 2차원 배열에 넣고
학생들의 이름은 다른 배열에 따로 넣었다.
import java.util.Scanner; /* * 학생 5명의 국영수 점수 관리하는 프로그램 * */ public class NestedArray { public static void main(String[] args) { // 학생 5명 국영수 점수 관리하는 2차원배열 int[][] scoreArray = new int[5][3]; // 학생 배열 가지는 String 배열 String[] nameArray = new String[5]; Scanner scan = new Scanner(System.in); for(int i = 0; i < scoreArray.length; i++) { System.out.println((i+1) + " 번 학생의 정보"); System.out.print("이름 : "); String name = scan.next(); System.out.print(name + "학생의 국어 점수 :"); scoreArray[i][0] = scan.nextInt(); System.out.print(name + "학생의 영어 점수 :"); scoreArray[i][1] = scan.nextInt(); System.out.print(name + "학생의 수학 점수 :"); scoreArray[i][2] = scan.nextInt(); // i에 이름 넣어주기 nameArray[i] = name; scan.nextLine(); // 버퍼메모리 지우기 } // 출력 for(int i = 0; i < scoreArray.length; i++) { System.out.println("====" +nameArray[i]+ "===="); System.out.println("국어\t영어\t수학\t"); for(int k = 0; k < scoreArray[i].length; k++) { System.out.println(scoreArray[i][k] + "\t"); } System.out.println(); printSumAndAvg(scoreArray[i]); } scan.close(); } // 총점과 평균구하는 메소드 private static void printSumAndAvg(int[] scoreArray) { int sum = 0; for(int i = 0; i < scoreArray.length; i++) { sum += scoreArray[i]; } double avg = sum/(double)scoreArray.length; System.out.println("총점 : " + sum); System.out.println("평균 : " + avg); } }
<풀이>
int[][] scoreArray = new int[5][3]; 은
[][][]
[][][]
[][][]
[][][]
[][][]
이렇게 되는데
각 행이 국영수 점수가 들어가고
열에 따라 학생들을 구분하게 된다.
이후 학생들의 이름 배열의 길이 만큼 for문을 실행해서 학생들의 이름을 입력받고
이 후 바로 학생들의 국영수 점수도 입력받는다.
학생들의 국영수 점수는 이미 바깥에서 학생 이름 배열 길이 만큼 이름을 입력받고 있기 때문에
for문을 쓰지 않고 그대로 입력받았다.
이차원배열의 경우 어떻게 입력을 받을까 많이 헷갈렸는데,
더보기scoreArray[i][0] = scan.nextInt();
코드를 보면, 0부터 학생 이름 배열 길이 만큼 증가하는 i 번 만큼
[0] : 국어
[1] : 영어
[2] : 수학 의 입력을 차례로 받는다.
위의 크기 2의 국영수 배열은 학생의 이름 수, 즉 학생의 수 만큼 반복한다.
정리하면
더보기scoreArray[0][0]
scoreArray[0][1]
scoreArray[0][2]
scoreArray[1][0]
scoreArray[1][1]
scoreArray[1][2]
....
이런 식으로 각 배열에 데이터가 들어갈 수 있다.
그런 후 따로 name이라는 변수를 선언해 입력받은 이름들을 학생 이름 배열에 넣어준다.
더보기nameArray[i] = name;
이후, scan.nextLine(); 를 이용해 앞서 scan.nextInt()로 인해 쌓인 버퍼메모리를 지워준다.
그렇지 않으면 다음 입력을 받을 때 입력 칸이 앞의 scan.nextInt(); 코드들로 생긴 엔터들로 이상하게 된다.
학생들의 이름정보 일이 끝났으면 다음은 점수를 출력해본다.
점수를 출력하는 코드는 점수 배열 scoreArray의 길이만큼 for문을 실행시켜 먼저 학생의 이름과 과목명 행을 나열한다.
그런 후 안쪽에 for문을 한번 더 실행해 배열 각 위치에 있는 점수 데이터들을 꺼내온다.
단. 이때는 scoreArray[i]의 길이 만큼 for문을 돌린다.
scoreArray.length를 했을 때는 단순히 scoreArray 배열의 길이 이므로 5이다.
그런데 scoreArray[i].length를 했을 때는 3이 나온다.
즉, 바깥의 for문으로는 학생 수 만큼 행 출력이 이루어진다. >> 5
그와 동시에 안쪽 for문은 과목 수 만큼 열 출력이 이루어진다 >> 3
또 메인 메소드 밖에 학생 점수의 총점과 평균을 구하는 메소드 printSumAndAverage()가 있다.
이 메소드는 점수 배열을 받아 점수 배열의 길이만큼
점수들을 더해서 sum 이라는 총합을 만들고
그 총합을 이용해서 avg라는 평균을 만들어 그 둘을 출력하는 메소드다.
# 가장 잘 본 점수 뽑아보기
미국 대입시험 SAT는 수학, 읽기, 쓰기 시험이 한달에 한번 열린다.
한 학생은 SAT를 3번 응시했고 그 중에서 가장 잘 나온 점수를 뽑아 볼 것이다.
import java.util.Scanner; public class NestedArray2 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int[][] scoreArray = new int[3][3]; // 3번씩 3과목을 응시했기 때문에 각각 3이다. for(int i = 0; i < scoreArray.length; i++) { System.out.println((i+1)+ "회차 입니다"); System.out.println("수학 : "); scoreArray[i][0] = scan.nextInt(); System.out.println("읽기 : "); scoreArray[i][1] = scan.nextInt(); System.out.println("쓰기 : "); scoreArray[i][2] = scan.nextInt(); } int[] maxScores = calculateMax(scoreArray); System.out.println("학생의 각 최고 점수 "); System.out.println("수학 : " + maxScores[0]); System.out.println("읽기 : " + maxScores[1]); System.out.println("쓰기 : " + maxScores[2]); scan.close(); } private static int[] calculateMax(int[][] scoreArray) { int[] maxScores = new int[3]; for(int i = 0; i < scoreArray.length; i++) { int mathMax = 0; int readingMax = 0; int writingMax = 0; for(int k = 0; k < scoreArray[i].length; k++) { // 삼항연산자 mathMax = mathMax <scoreArray[i][0] ? scoreArray[i][0] : mathMax; readingMax = readingMax <scoreArray[i][1] ? scoreArray[i][1] : readingMax; writingMax = writingMax <scoreArray[i][2] ? scoreArray[i][2] : writingMax; } maxScores[0] = mathMax; maxScores[1] = readingMax; maxScores[2] = writingMax; } return maxScores; } }
<풀이>
더보기int[][] scoreArray = new int[3][3];
3번씩 3과목을 응시하므로 각각 크기가 3인 이차원 배열을 선언한다.
내가 잠시 헷갈렸던 부분이 있는데
대괄호 안에 들어간 정수는 배열의 크기를 말한다.
처음에 나는 인덱스 번호와 헷갈려서 3이라고 적혀 있으면 크기 4의 배열이라고 생각했다.
그런데 그게 아니라 크기 3의 배열을 선언했다는 의미이다.
이후 for문을 이용해 점수를 입력받는다.
여기서 i는 회차를 의미하므로 총 3회 반복된다.
for문은 점수 배열의 길이 3만큼 실행되어 수학, 읽기, 쓰기 과목 각각의 점수를 입력받는다.
입력받는 방식은 위의 프로그램과 똑같다.
더보기scoreArray[i][0] = scan.nextInt();
과목 수 3만큼 0에서 2까지의 배열을 나열해 입력을 받는다.
역시 앞의 i는 응시 회차이다.
여기까지 하고 최고점수를 찾는 calculateMax메소드를 만든다.
먼저 최고점수를 넣을 수 있는 배열 maxScores를 만든다.
그런 후 점수 배열의 길이만큼 for문을 돌린다.
for 문 안에 각 과목의 최고점 mathMax, readingMax, writingMax를 0으로 초기화 한다.
그리고 각 과목의 최고점을 찾는데에 삼항연산자를 사용한다.
if문을 사용할 수도 있지만 여기서는 좀 더 간단하게 삼항연산자를 이용해보자.
더보기삼항연산자는 어딘가에 값을 정할 때 사용된다.
if문과 switch 문은 조건이 맞으면 특정 메소드나 어떤 코드를 실행하지만
삼항연산자는 오직 값을 결정할 때만 쓰인다.
사용법은 아래와 같다
값을 결정할 곳 = 조건식 ? 참일때 값 : 거짓일 때 값
여기서 쓰인 삼항연산자를 보면
더보기mathMax = mathMax < scoreArray[i][0] ? scoreArray[i][0] : mathMax;
점수 배열에 math 점수가 들어가는 배열의 위치를 통해 앞서 초기화 해놓은 mathMax 값과 비교를 한다. 그런 후 scoreArray 값이 mathMax 값 보다 크면 그 값이 그대로 mathMax에 들어가 math과목의 최고점이 된다.
다른 과목들도 위와 같이 해준다.
이 과정은 for문으로 인해 점수 배열의 길이만큼 진행된다.
그런 후 maxScore 배열의 인덱스들에 과목들의 최고점을 각각 넣어준다
더보기maxScores[0] = mathMax;
위와 같이 최고점을 찾아준 메소드 작업이 끝나면 이제 main 메소드에서 쓰기만 하면 된다.
main 메소드 안에서 최고점을 넣을 maxScore 배열을 선언해 준 후 그 값으로
앞서 만들었던 calculateMax 메소드를 불러와 매개변수로 점수 배열을 넣는다.
그런 후 최고점을 출력하면 끝난다.
# 자동차 정보 관리 프로그램
이 프로그램에선 차량 소유주를 가진 String 배열 1개
소유주의 차종을 가진 String 배열 1개
해당 차의 연식과 가격을 가지고 있는 int 2차원 배열 1개가 있다.
단 5명의 값을 입력하고 각 정보가 출력되게 한다.
import java.util.Scanner; public class NestedArray3 { private final static int SIZE = 5; private final static int INT_COL = 2; public static void main(String[] args) { Scanner scan = new Scanner(System.in); // 소유주 담당 배열 String[] owners = new String[SIZE]; // 차량 담당 배열 String[] types = new String[SIZE]; // 연식-가격 담당 배열 int[][] yearPriceArray = new int[SIZE][INT_COL]; insert(owners, types, yearPriceArray); print(owners, types, yearPriceArray); } // 입력메소드 private static void insert(String[] nameArray, String[] carArray, int[][] yearPrice) { Scanner scan = new Scanner(System.in); for(int i = 0; i < nameArray.length; i++) { System.out.print("이름 : "); nameArray[i] = scan.nextLine(); System.out.print("차종 : "); carArray[i] = scan.nextLine(); System.out.print("연식 : "); yearPrice[i][0] = MyScanner.nextInt(scan); System.out.print("가격 : "); yearPrice[i][0] = MyScanner.nextInt(scan); } scan.close(); } // 출력메소드 private static void print(String[] owners, String[] types, int[][] yearPriceArray) { for(int i = 0; i < owners.length; i++) { System.out.println("차주명\t차종\t연식\t가격\t"); System.out.printf("%s\t %s\t %d\t %d\t \n", owners[i], types[i], yearPriceArray[i][0], yearPriceArray[i][1]); } } }
이 프로그램에선 입력 메소드와 출력메소드를 두개 만들어 줬다.
먼저 배열의 상수선언을 각각 했다.
매직넘버가 나오지 않게 함이다.
내가 만든 배열은 우선 차 소유주 담당 배열, 차량 담당 배열, 차량 연식-가격 담당 배열이다.
우선 입력 메소드 insert()를 보자.
입력메소드의 매개변수는 이름을 넣을 nameArray, 차종을 넣을 carArray, 연식과 가격을 넣을 yearPrice 이차원배열이 있다.
여기서 각 데이터들을 입력받는다.
먼저 Scanner 객체를 선언해주는데 여기서는 앞선 프로그램과 다른 경우를 두었다.
바로 Scanner 클래스를 따로 만들어 준것이다.
MyScanner.class
import java.util.Scanner; public class MyScanner { public static int nextInt(Scanner scanner) { int userNumber = scanner.nextInt(); scanner.nextLine(); return userNumber; } }
클래스에서는 앞서 연속적으로 입력을 받을 시 버퍼메모리가 쌓여
나중에 입력 받는 칸이 이상하게 밀려나는 현상이 있어 scan.nextLine();을 단독으로 사용해
버퍼메모리를 지우는 작업을 했었는데 그 작업을 해준다.
다시 돌아와서,
이름, 차종을 차례로 입력받고
연식, 가격을 MyScanner를 이용해 받는다.
그 다음은 출력메소드 print()이다.
이 메소드에서는 차주 owners 배열, 차종 types 배열, 가격과 연식 yearPriceArray 배열을 매개변수로 받는다.
그리고 for문을 이용해 차 주 배열의 길이 만큼 실행한다.
여기서 앞서 입력받은 차에 대한 배열 데이터를 출력한다.
이렇게 두 메소드를 만들고 다시 main 메소드로 들어가
두 메소드를 차례로 호출한다.
단, 여기서 메소드를 호출할 때는 메소드의 매개변수 이름과는 상관없이
그 전에 main 메소드 안에서 선언했던 배열의 이름과 동일하게 매개변수로 불러와야 작동이 된다.
# 배열의 길이를 늘리는 프로그램
기존 크기 3 배열의 크기를 늘려보는 프로그램이다.
public class NestedArray4 { public static void main(String[] args) { int[] arr = new int[3]; System.out.println(arr.length); arr = expand(arr); System.out.println(arr.length); } public static int[] expand(int[] array) { int[] temp = new int[array.length]; for(int i = 0; i < array.length; i++) { temp[i] = array[i]; } array = new int[temp.length + 1]; for(int i = 0; i < temp.length; i++) { array[i] = temp[i]; } return array; } }
ArrayList라는 편리한 기능도 있지만..
여기서는 고정크기 배열을 이용해서 크기를 증가시키는 메소드를 만들어 본다.
temp 라는 기존의 데이터를 임시보관을 할 배열을 만들어야한다.
이 temp에 데이터들을 복사하고 배열을 늘린 후 임시보관 데이터들을 다시 복사해오는
조금은 귀찮은 과정을 거친다.
temp는 우선 기존의 array의 길이와 같은 크기의 배열이여야한다.
그런 후 array의 길이 만큼 for문을 돌려 array의 데이터를 temp 안에 넣는다.
곧장 array를 늘리지 않는 이유는 자칫 기존의 데이터에 손상이 갈 수 있기 때문이라고 생각하면 될 듯 하다.
이후 어차피 array와 temp는 원본이냐 아니냐의 차이 뿐, 같은 상태이기 때문에
데이터를 복사해놓은 temp에다 +1 을 해서 크기를 늘려준다.
이후 다시 for문을 이용해 늘린 temp의 길이 만큼 반복하며 array에 temp 값을 넣어준다.
그런 후 array를 return 하면 array는 결국 temp와 같은 형태이기 때문에 길이가 1증가한 배열이 된 것이다.
위의 expand 메소드를 호출한 후에 array.length를 해보면 4가 출력되는 것을 확인할 수 있다.
'프로그래밍 > TIL(국비과정)' 카테고리의 다른 글
TIL #6 - 배열 활용 (2) (0) 2020.04.01 TIL #6 - 배열 활용 (1) (0) 2020.04.01 TIL #4 - 메소드, 배열 등 (0) 2020.03.30 TIL #3 - Java 기초 등 (0) 2020.03.28 TIL #2 - Java 기초 등 (0) 2020.03.26