210502 일요일 5일차
# 3~4일차 복습
•
배열의 처음에 요소를 추가할 때 변형자 함수가 없다면 배열에 있던 기존 모든 요소를 한 칸씩 뒤로 이동시킨 다음 새 데이터를 추가해야 한다. unshift()는 한 번에 여러 요소를 배열 앞으로 추가할 수도 있다.
•
배열의 앞 요소를 제거할 때 변형자 함수가 없다면 요소를 추가할 때와 마찬가지로 비효율적이다. 비효율적인 동작 후에 맨 끝에 불필요한 값이 저장된다. 마지막 콤마가 출력된 것으로 알 수 있다.
shift() 함수를 이용하면 간단히 배열의 맨 처음 요소를 제거할 수 있다.
let nums = [9,1,2,3,4,5];
nums.shift();
console.log(nums);// 1,2,3,4,5
JavaScript
복사
•
pop()과 shift()는 제거된 요소를 반환하므로 필요하면 이 요소를 변수에 저장할 수 있다.
•
splice()
•
시작 인덱스(어느 지점부터 요소를 추가할 것인지)
•
삭제할 요소의 개수(요소를 추가할 때는 O)
•
배열에 추가할 요소들
let nums = [1, 2, 3, 7, 8, 9];
let newElements = [4, 5, 6];
nums.splice(3, 0, ...newElements);
console.log(nums);// 1,2,3,4,5,6,7,8,9
JavaScript
복사
시작 인덱스 3(nums[3]), 0이므로 요소 추가, 그 다음부터는 추가하려는 요소 목록을 자유롭게 제공하면 된다.
// splice() : 중간에 삭제let nums = [1, 2, 3, 100, 200, 300, 400, 4, 5];
nums.splice(3, 4);
console.log(nums);// 1,2,3,4,5
JavaScript
복사
시작 인덱스 3(nums[3])부터 요소 4개를 삭제한다.
•
sort() 함수가 배열 요소를 순서대로 정렬하며 특히 문자열을 정렬할 때 유용하다.
// sort() 숫자 정렬 함수function compare(num1, num2) {
return num1 - num2;
}
let nums = [3, 1, 2, 100, 4, 200];
nums.sort(compare);
console.log(nums);// 1,2,3,4,100,200
JavaScript
복사
•
배열을 만들지 않는 반복자 함수로 forEach() 함수가 있다. 배열의 모든 요소에 인자로 받은 함수를 호출한다.
function square(num) {
console.log(num, num * num);
}
let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
nums.forEach(square);
JavaScript
복사
•
every()는 불린 함수를 배열에 적용해 배열의 모든 요소가 참이면 true를 반환한다.
// every() : 불린 함수를 배열에 적용, 모든 요소가 참이면 true 반환.function isEven(num) {
return num % 2 == 0;
}
let nums = [2, 4, 6, 8, 10];
let even = nums.every(isEven);
if (even) {
console.log("all numbers are even");
} else {
console.log("not all numbers are even");
}
JavaScript
복사
•
some() 함수는 배열 요소 중에 한 요소라도 인자로 받은 불린 요소의 기준을 만족하면 true를 반환한다.
// some() : 불린 함수를 배열에 적용, 하나라도 요소가 참이면 true 반환.function isEven(num) {
return num % 2 == 0;
}
let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let someEven = nums.some(isEven);
if (someEven) {
console.log("some numbers are even");
} else {
console.log("not all numbers are even");
}
nums = [1, 3, 5, 7, 9];
someEven = nums.some(isEven);
if (someEven) {
console.log("some numbers are even");
} else {
console.log("no numbers are even");
}
JavaScript
복사
•
reduce() 함수를 이용해 문자열을 연결할 수도 있다.
// reduce() : 문자열도 연결할 수 있다.function concat(accumulatedString, item) {
return accumulatedString + item;
}
let words = ["the ", "quick ", "brown ", "fox "];
let sentence = words.reduce(concat);
console.log(sentence);// the quick brown fox
JavaScript
복사
•
문자열에 map() 사용
function first(word){
return word[0];
}
let words = ["for", "your", "information"]
let acronym = words.map(first)
console.log(acronym.join(""));// "fyi"
JavaScript
복사
toString() 을 이용해 요소를 출력하면 콤마가 표시되므로 공백문자열을 분리자로 사용하도록 join()을 호출
•
filter()는 불린 함수를 만족하는 요소를 포함하는 새로운 배열을 반환한다.
// filter() : 불린 함수를 만족하는 요소를 포함하는 새로운 배열을 반환function isEven(num) {
return num % 2 == 0;
}
function isOdd(num) {
return num % 2 != 0;
}
let nums = [];
for (let i = 0; i < 20; ++i) {
nums[i] = i + 1;
}
let evens = nums.filter(isEven);
console.log("Even numbers: ");
console.log(evens);
let odds = nums.filter(isOdd);
console.log("Odd numbers: ");
console.log(odds);
JavaScript
복사
•
이차원 베열
Array.matrix = function (numrows, numcols, initial) {
let arr = [];
for (let i = 0; i < numrows; ++i) {
let columns = [];
for (let j = 0; j < numcols; ++j) {
columns[j] = initial;
}
arr[i] = columns;
}
return arr;
};
let arr = Array.matrix(3, 2, 3);
console.log(arr);
JavaScript
복사
CH2 배열
2.8 객체에 포함된 배열
한 주 동안 관찰된 가장 높은 온도를 저장하는 객체를 만든다. 새 온도를 추가하는 기능, 저장된 온도의 평균을 계산하는 기능을 포함한다.
function weekTemps() {
this.dataStore = [];
this.add = add;
this.average = average;
}
function add(temp) {
this.dataStore.push(temp);
}
function average() {
let total = 0;
for (let i = 0; i < this.dataStore.length; ++i) {
total += this.dataStore[i];
}
return total / this.dataStore.length;
}
let thisWeek = new weekTemps();
thisWeek.add(52);
thisWeek.add(55);
thisWeek.add(61);
thisWeek.add(65);
thisWeek.add(55);
thisWeek.add(50);
thisWeek.add(52);
thisWeek.add(49);
console.log(thisWeek.average());
JavaScript
복사
2.9 연습문제
#1. 객체에 학생들의 점수 집합을 저장하는 grades 객체를 만드시오. 점수를 추가하는 함수, 학생의 평균 점수를 출력하는 기능을 객체에 추가하시오.
function grades() {
this.dataStore = [];
this.add = add;
this.average = average;
}
function add(grade) {
this.dataStore.push(grade);
}
function average() {
let total = 0;
for (let i = 0; i < this.dataStore.length; ++i) {
total += this.dataStore[i];
}
return total / this.dataStore.length;
}
let grade = new grades();
grade.add(800);
grade.add(1000);
grade.add(1200);
grade.add(1400);
console.log(grade.average());// 1100
JavaScript
복사
점수를 추가하기 위해 dataStore라는 배열에 push를 이용하였다. 평균 점수는 배열의 모든 요소를 더한다음 배열의 요소 개수로 나눈 값을 반환하여 그 값을 console.log로 출력했다.
#2. 배열의 단어 집합을 저장한 다음 배열의 내용을 정방향 또는 역방향으로 출력하는 기능을 구현하시오.
let arr = ["D", "C", "R", "L", "J"];
console.log(arr);
console.log(arr.reverse());
JavaScript
복사
#3. 이차원 배열을 이용해 월간 온도 자료를 저장하도록 weeklyTemps 객체를 고치시오. 월간 평균, 지정한 주의 평균, 모든 주의 평균을 출력하는 함수를 만드시오.
function weekTemps() {
this.dataStore = Array.matrix(4, 7, 0);// 이차원 배열 4주, 7일this.add = add;
this.wAverage = wAverage;
this.wAverageAll = wAverageAll;
this.mAverage = mAverage;
}
Array.matrix = function (numrows, numcols, initial) {
let arr = [];
for (let i = 0; i < numrows; ++i) {
let columns = [];
for (let j = 0; j < numcols; ++j) {
columns[j] = initial++;
}
arr[i] = columns;
}
return arr;
};
function add(temp) {
this.dataStore.push(temp);
}
function wAverage(i) {
let total = 0;
if (0 < i && i < this.dataStore.length) {
// 자연수만 받기 > 정규표현식 사용for (let j = 0; j < this.dataStore[i - 1].length; ++j) {
total += this.dataStore[i - 1][j];
}
return total / this.dataStore[i - 1].length;
} else {
return "1 ~ " + this.dataStore.length + " 주로 입력하세요";
}
}
function wAverageAll() {
let total = 0;
let arr = [];
for (let i = 0; i < this.dataStore.length; ++i) {
for (let j = 0; j < this.dataStore[i].length; ++j) {
total += this.dataStore[i][j];
}
arr.push(i + 1 + "주의 평균 : " + total);
total = 0;// 주간 총합 초기화
}
return arr;
}
function mAverage() {
let total = 0;
let mTotal = 0;
for (let i = 0; i < this.dataStore.length; ++i) {
for (let j = 0; j < this.dataStore[i].length; ++j) {
total += this.dataStore[i][j];
}
mTotal += total;
total = 0;// 주간 총합 초기화
}
return mTotal / (this.dataStore.length * this.dataStore[0].length);
}
let thisWeek = new weekTemps();
console.log(thisWeek.wAverage(1));// 첫째 주 평균console.log(thisWeek.wAverageAll());// 모든 주 평균console.log(thisWeek.mAverage());// 월간 평균
JavaScript
복사
CH3 리스트
3.1 리스트 ADT
리스트는 위치를 가리키는 프로퍼티를 포함한다. 리스트에는 front, end 프로퍼티가 있다. next() 함수로 리스트의 현재 요소에서 다음 요소로 이동할 수 있으며 prev() 함수로 현재 요소에서 이전 요소로 이동할 수 있다. moveTo(n) 함수를 이용하면 n 번째 위치로 한 번에 이동할 수 있다. currPos() 함수는 리스트의 현재 위치를 가리킨다.
3.1 List 클래스 구현
생성자 함수 정의
function List() {
this.listSize = 0;
this.pos = 0;
this.dataStore = [];
this.clear = clear;
this.find = find;
this.toString = toString;
this.insert = insert;
this.append = append;
this.remove = remove;
this.front = front;
this.end = end;
this.prev = prev;
this.next = next;
this.length = length;
this.currPos = currPos;
this.moveTo = moveTo;
this.getElement = getElement;
this.contains = contains;
}
JavaScript
복사
3.2.1 Append: 리스트에 요소 추가
리스트의 다음 가용 위치(listSize)에 새 요소 추가하는 함수이다.
function append(element) {
this.dataStore[this.listSize++] = element;
}
JavaScript
복사
3.2.2 Find: 리스트의 요소 검색
remove()는 가장 구현이 어렵다. 삭제하려는 요소를 찾은 다음 그 요소를 삭제하고 나머지 요소를 왼쪽으로 이동시켜 자리를 메워야 한다. 우선 요소를 찾는 헬퍼 함수 find()를 구현한다.
// find() : remove는 삭제할 요소를 찾고, 요소를 삭제하고, 나머지 배열 요소를 왼쪽으로 이동시켜 자리를 메운다. 삭제할 요소를 찾을 헬퍼 함수function find(element) {
for (let i = 0; i < this.dataStore.length; ++i) {
if (this.dataStore[i] == element) {
return i;
}
}
return -1;
}
JavaScript
복사
3.2.3 Remove: 리스트의 요소 삭제
find()는 루프를 돌면서 요소를 검색하고 발견하면 요소의 위치를 반환한다. 찾지 못하면 -1 을 반환한다. remove()는 find()의 반환값으로 에러를 검사한다. 이 반환값을 splice()에 넘겨주어 원하는 요소를 삭제한 다음 배열을 연결한다. 요소를 삭제했다면 true, 못했다면 false를 반환한다.
// remove() : find()의 반환값을 splice 함수에 넘겨주어 원하는 요소를 삭제한 다음 dataStore 배열을 연결한다. 요소를 삭제하면 true, 못하면 false 반환function remove(element) {
let foundAt = this.find(element);
if (foundAt > -1) {
this.dataStore.splice(foundAt, 1);
--this.listSize;
return true;
}
return false;
}
JavaScript
복사
3.2.4 Length: 리스트의 요소 개수
function length() {
return this.listSize;
}
JavaScript
복사
3.2.5 toString: 리스트의 요소 확인
function toString(){
return this.dataStore;
}
JavaScript
복사
# 중간 테스트 코드
// 리스트 중간 테스트function List() {
this.listSize = 0;
// this.pos = 0;this.dataStore = [];
// this.clear = clear;this.find = find;
this.toString = toString;
// this.insert = insert;this.append = append;
this.remove = remove;
// this.front = front;// this.end = end;// this.prev = prev;// this.next = next;this.length = length;
// this.currPos = currPos;// this.moveTo = moveTo;// this.getElement = getElement;// this.contains = contains;
}
function append(element) {
this.dataStore[this.listSize++] = element;
}
// find() : remove는 삭제할 요소를 찾고, 요소를 삭제하고, 나머지 배열 요소를 왼쪽으로 이동시켜 자리를 메운다. 삭제할 요소를 찾을 헬퍼 함수function find(element) {
for (let i = 0; i < this.dataStore.length; ++i) {
if (this.dataStore[i] == element) {
return i;
}
}
return -1;
}
// remove() : find()의 반환값을 splice 함수에 넘겨주어 원하는 요소를 삭제한 다음 dataStore 배열을 연결한다. 요소를 삭제하면 true, 못하면 false 반환function remove(element) {
let foundAt = this.find(element);
if (foundAt > -1) {
this.dataStore.splice(foundAt, 1);
--this.listSize;
return true;
}
return false;
}
function length() {
return this.listSize;
}
function toString() {
return this.dataStore;
}
let names = new List();
names.append("C");
names.append("R");
names.append("B");
console.log(names.toString());
names.remove("R");
console.log(names.toString());
JavaScript
복사
3.2.6 Insert: 리스트에 요소 삽입
insert() 는 리스트의 기존 요소 뒤에 새로운 요소를 삽입하게 된다. find로 기존 요소의 위치를 찾아 해당 위치 +1 에 요소를 추가한 다음 listSize를 1만큼 증가시킨다.
function insert(element, after) {
let insertPos = this.find(after);
if (insertPos > -1) {
this.dataStore.splice(insertPos + 1, 0, element);
++this.listSize;
return true;
}
return false;
}
JavaScript
복사
3.2.7 리스트의 모든 요소 삭제
clear()는 delete 명령어로 배열을 삭제한다음 빈 배열을 다시 만든다. listSize와 pos도 0(시작 위치)으로 초기화한다.
function clear() {
delete this.dataStore;
this.dataStore.length = 0;
this.listSize = this.pos = 0;
}
JavaScript
복사
3.2.8 Contains: 리스트에 특정 값이 있는지 판단
function contains(element) {
for (let i = 0; i < this.dataStore.length; ++i) {
if (this.dataStore[i] == element) {
return true;
}
}
return false;
}
Java
복사
3.2.9 리스트 탐색
function List() {
this.listSize = 0;
this.pos = 0;
this.dataStore = [];
// this.clear = clear;// this.find = find;// this.toString = toString;// this.insert = insert;this.append = append;
// this.remove = remove;this.front = front;
this.end = end;
this.prev = prev;
this.next = next;
// this.length = length;this.currPos = currPos;
this.moveTo = moveTo;
this.getElement = getElement;
// this.contains = contains;
}
// @ : 리스트 추가용function append(element) {
this.dataStore[this.listSize++] = element;
}
// 3.2.9function front() {
this.pos = 0;
}
function end() {
this.pos = this.listSize - 1;
}
function prev() {
if (this.pos > 0) {
--this.pos;
}
}
function next() {
if (this.pos < this.listSize - 1) {
++this.pos;
}
}
function currPos() {
return this.pos;
}
function moveTo(position) {
this.pos = position;
}
function getElement() {
return this.dataStore[this.pos];
}
let names = new List();
names.append("C");
names.append("R");
names.append("Cy");
names.append("J");
names.append("B");
names.append("D");
// 첫번째 요소로 이동
names.front();
console.log(names.getElement());
// 한 요소 뒤로 이동
names.next();
console.log(names.getElement());
// 두 요소 뒤로 이동했다가 한 요소 앞으로 이동
names.next();
names.next();
names.prev();
console.log(names.getElement());// C
JavaScript
복사
3.3 리스트와 반복
반복자를 이용하면 List 클래스 내부 저장소를 직접 참조하지 않고 리스트를 탐색할 수 있다. 리스트의 front, end, prev, next, currPos를 이용해 반복자를 구현할 수 있다.
반복자는 배열의 인덱스에 비해 아래의 장점이 있다.
•
리스트 요소에 접근할 때 내부 데이터 저장소가 무엇인지 걱정할 필요가 없다.
•
리스트에 새 요소를 추가했을 때 현재 인덱스가 쓸모 없는 값이 되는 반면 반복자를 이용하면 리스트가 바뀌어도 반복자를 갱신할 필요가 없다.
•
List 클래스에 사용하는 데이터 저장소의 종류가 달라져도 이전과 같은 방식으로 요소에 접근할 수 있다.
반복자 예제
for (names.front(); names.currPos() < names.length(); names.next()) {
console.log(names.getElement);
}
JavaScript
복사
현재 위치를 리스트 앞으로 설정(front())한다. 그리고 currPos() 가 리스트 길이보다 작을 때 루프를 반복한다. 루프를 돌 때마다 next()로 한 요소씩 전진한다.
반대 방향 탐색 예제
for (names.end(); names.currPos() >= 0; names.prev()) {
console.log(names.getElement);
}
JavaScript
복사
현재 위치를 마지막 요소로 한다.(end()) prev()를 이용하여 현재 위치가 0보다 크거나 같을 때 현재 위치를 뒤로 이동시킨다.
리스트를 탐색할 때만 반복자를 사용해야 하며 요소 추가/삭제에는 사용하면 안된다.
3.4 리스트 기반 애플리케이션
비디오 대여 상점을 운영할 수 있는 시스템에서 리스트를 어떻게 활용할 수 있는지 알아본다.
3.4.1 텍스트 파일 읽기
1.
The Godfather
2.
The Godfather: Part II
3.
The Dark Knight
6.
The Lord of the Rings: The Return of the King
10.
11.
12.
14.
The Lord of the Rings: The Two Towers
15.
16.
GoodFellas
18.
위 내용으로 텍스트 파일을 만든다.
let fs = require("fs");
fs.readFile("films.txt", "utf8", function (err, data) {
let movies = data.split("\n");
console.log(movies);
});
JavaScript
복사
File System 모듈 - 한 눈에 끝내는 Node.js. 파일 처리와 관련된 작업을 하는 모듈로, 보통 FileSystem을 줄여서 fs 모듈이라고 줄여 부릅니다.(책에 있는 코드와 다릅니다.)
텍스트 파일의 내용이 배열로 저장될 때 개행 문자가 공백으로 치환되므로 문자열 배열에서 문제가 될 수 있다. 따라서 trim()을 이용해 각 요소의 공백을 제거하는 루프를 추가한다.
function createArr(file) {
let fs = require("fs");
let arr = fs.readFile(file, "utf8", function (err, data) {
let arr = data.split("\n");
// console.log(movies);for (let i = 0; i < arr.length; ++i) {
arr[i] = arr[i].trim();
}
return arr;
});
return arr;
}
JavaScript
복사
3.4.2 리스트로 상점을 관리하기
movies 배열의 내용을 리스트로 저장한다.
let movieList = new List();
for (let i = 0; i < movies.length; ++i) {
movieList.append(movies[i]);
}
function displayList(list) {
for (list.front(); list.currPos() < list.length(); list.next()) {
console.log(list.getElement());
}
}
JavaScript
복사
displayList()가 문자열 등 네이티브 형식을 포함하는 리스트와는 잘 동작하지만 Customer 객체에서 잘 작동하지 않아 개선이 필요하다.
function displayList(list) {
for (list.front(); list.currPos() < list.length(); list.next()) {
if (list.getElement() instanceof Customer) {
console.log(
list.getElement()["name"] + ", " + list.getElement()["movie"]
);
} else {
console.log(list.getElement());
}
}
}
JavaScript
복사
instanceof 연산자를 이용해 Customer 객체인지 하나씩 확인하고 Customer 객체면 두 프로퍼티를 인덱스로 활용해 고객이 빌린 영화 이름을 가져온다. 해당 객체가 아니면 요소를 그대로 반환한다.
let customers = new list();
function Customer(name, movie) {
// 고객명과 고객이 빌린 영화 이름을 포함하는 객체 생성자 함수this.name = name;
this.movie = movie;
}
function checkOut(name, movie, filmList, customerList) {// 고객이 영화를 대여하는 기능의 함수if (movieList.contains(movie)) {// 영화를 이용할 수 있으면 상점 영화 목록에서 지우고 고객의 영화 목록에 추가한다.let c = new Customer(name, movie);
customerList.append(c);
filmList.remove(movie);
} else {
console.log(movie + " is not available.");
}
}
JavaScript
복사
checkOut() 은 영화를 대여할 수 있는지 확인한다. 대여할 수 있는 상태면 영화 제목, 고객명을 이용해 Customer 객체를 만든다. 만든 객체를 고객 리스트로 추가하고 영화 리스트에서 대여할 영화를 삭제한다. 대여할 수 없는 상태면 간단한 메시지를 출력한다.
checkOut()을 테스트하는 코드
let movies = createArr("films.txt");
let movieList = new List();
let customers = new List();
for (let i = 0; i < movies.length; ++i) {
movieList.append(movies[i]);
}
console.log("Available movies: \n");
displayList(movieList);
checkOut("Jane Doe", "The Godfather", movieList, customers);
console.log("\nCustomer Rentals: \n");
displayList(customers);
JavaScript
복사
실행하면 "The Godfather"가 삭제된 영화 목록이 출력되고 고객이 대여한 영화 리스트가 출력된다.