자료구조와 자료형 : 배열

라용·2022년 11월 25일
0

모던 JavaScript 튜토리얼 내용 일부를 정리 요약한 내용입니다. 더 자세한 설명은 원문 링크를 참고하세요.

생각

배열 파트의 긴 스크롤을 보면서, 배열은 대충 아니까 넘어갈까 했지만 그건 나의 오산이었다. 정리하다보니 새롭게 알게되는 것이 또 많다. 큐랑 스택이라는 자료구조는 대충 알고 있었는데, 이것을 배열의 메서드랑 연결해서 생각하지 않았고, 배열의 앞 요소를 빼는 것이 성능에 영향을 준다는 것도 지금까지 인식하지 못했다. 배열에 for.. in 을 사용하지 말라는 것은 어렴풋이 알았지만 그 구체적인 이유는 잘 몰랐고, length 프로퍼티가 요소의 갯수가 아닌 가장 큰 인덱스의 +1 이라는 것도 새롭게 알았다. (빈 배열의 숫자 인덱스로 값을 넣으면 그 인덱스 값의 +1이 length 임)


정리

객체는 순서를 고려하지 않고 값을 저장하지만, 개발을 하다보면 순서를 고려해야 할 경우가 많습니다. 이런 문제를 해결하기 위해 순서를 고려하는 컬랙션인 배열을 사용합니다.

배열 선언

배열은 아래와 같이 만들 수 있고, 대괄호 안에 추가 요소를 넣어줄 수 있습니다. 각 요소는 0부터 시작하는 숫자 인덱스가 매겨지고 이 인덱스로 각 요소를 선택할 수 있습니다. 선택한 값을 수정하거나 새로운 값을 추가하는 것도 가능합니다. 그리고 length 를 사용하면 배열에 담긴 요소의 갯수를 알 수 있습니다.

let arr = [];

let document = ["배열", "객체", "문자열"]

document[0] // 배열
document[1] // 객체
document[2] // 문자열

doucment[1] = "감자" // 객체가 감자로 바뀜
document[3] = "고구마" // 네번째 요소로 고구마 추가

document.length // 4

pop, push 와 shift, unshift

배열을 사용해 만들 수 있는 대표적인 자료구조로 큐(queue)가 있습니다. 배열과 마찬가지로 순서가 있는 컬렉션을 저장하는 데 사용합니다. 배열의 메소드 push, pop 을 사용하면 맨 끝에 요소를 추가하거나, 제일 앞 요소를 빼내 남은 요소를 앞으로 밀어줄 수 있습니다. 화면에 순차적으로 메세지를 띄울 때 큐와 같은 자료구조를 사용하게 됩니다. 배열은 스택(stack)이라는 자료 구조를 구현할 때도 쓰이는데 스택은 큐와 달리 한쪽이 막혀 있어서, 요소 끝에 추가했다면, 오소 끝에부터 추출할 수 있습니다.

스택은 후입선출 Last-In-First-Out, LIFO 라고 부르고, 큐는 선입선출 First-In-First-Out, FIFO 라고 부릅니다. 이렇게 처음이나 끝에 요소를 더하거나 빼주는 연산을 제공하는 자료구조를 컴퓨터 과학 분야에서는 데큐 (deque, Double Ended Queue)라고 부릅니다.

pop 은 배열 끝 요소를 제거하고, 제거한 요소를 반환합니다.

let document = ["배열", "객체", "문자열"]

documnt.pop() // '문자열'
documnet // "배열", "객체"

push 는 배열 끝에 요소를 추가합니다.

let document = ["배열", "객체", "문자열"]

documnt.push("쥬스") // 
documnet // "배열", "객체", "문자열", "쥬스"

shift 는 배열 앞 요소를 제거하고 제거한 요소를 반환합니다.

let document = ["배열", "객체", "문자열"]

documnt.shift() // '배열'
documnet // "객체", "문자열"

unshift 는 배열 앞에 요소를 추가합니다.

let document = ["객체", "문자열"]

documnt.unshift('배열') // 
documnet // "배열", "객체", "문자열"

push 와 unshift 는 여러개의 요소를 한번에 더할 수도 있습니다.

배열 내부 동작 원리

배열은 키를 숫자로 가지는 특벽한 종류의 객체입니다. 기존 객체처럼 참조를 통해 복사할 수 있고, 자바스크립트 엔진은 배열 요소를 인접한 메모리 공간에 차례로 저장해 연산 속도를 높입니다. 배열은 순서가 있는 자료를 저장하는 용도로 만들어진 특수한 자료구조로 이에 맞게 배열 내장 메서드들도 만들어졌습니다. 아래처럼 사용하면 배열에만 적용되는 최적화 기법이 작동하지 않으니 주의해야 합니다.

arr.test = 5 // 숫자가 아닌 값을 프로퍼티 키로 사용
arr[0] 
arr[1000] // 0과 1000 사이 값이 없는 경우 
arr[900]
arr[899] // 요소를 역순으로 채우는 경우

성능

배열 끝 요소를 관리하는 push, pop 은 빠르지만 배열의 앞 요소를 관리하는 shift, unshift 는 느립니다. 배열 앞 요소를 제거하면 모든 요소가 앞으로 이동하며 인덱스가 수정되어야 하고 length 값도 갱신해야 합니다. 메모리 관련 연산이 많아집니다. push, pop 은 끝에 있는 요소만 지우거나 추가하므로 전체 배열의 인덱스가 바뀔 필요없이 length 만 수정하면 됩니다.

반복문

for 문은 인덱스를 사용해 배열을 순회하는 오래된 방법입니다. 인덱스 없이 배열의 값만 얻어야 한다면 for .. of 를 사용하는 것이 좋습니다.

let arr = ['사과', '오렌지', '배'];

// 아래 반복문은 같은 값을 반환

for (let i = 0; i < arr.length; i++) {
    alert(arr[i]);
}

for (let item of arr) {
    alert(item);
}

배열은 객체형에 속해서 for ..in 을 사용할 수도 있지만 권장하지 않습니다. 브라우저나 기타 호스트 환경에서 쓰이는 객체 중 배열과 유사한 유사배열의 경우 키가 숫자형이 아닌 것도 있어서, for .. in 으로 순회 시 문제가 발생할 수 있고, 객체 최적화되어 있어서 배열에 사용시 10-100배 정도 느립니다.

length 프로퍼티

정확히 말하면 length 프로퍼티는 배열 내 요소의 갯수가 아닌 가장 큰 인덱스에 1을 더한 값입니다. 아래와 같이 사용하지 않도록 유의해야 합니다.

let arr = [];
arr[12] = '렝스'

arr.length; // 13 - 요소는 1개인데 그 1개의 인덱스가 12이므로

그리고 length 의 값을 수동으로 감소시키면 그 길이만큼 배열이 잘립니다. 이런 특징을 활용해 arr.length = 0; 으로 배열을 비울 수 있습니다.

다차원 배열

배열 안의 배열이 담기는 것을 다차원 배열이라고 합니다. 행렬을 저장할 때 다차원 배열을 사용합니다.

let matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

matrix[1][1]; // 5

입력한 숫자의 합 구하기

아래 조건을 만족하는 함수 sumInput() 을 작성합니다.

  • prompt 창으로 숫자 입력하고 입력된 값을 배열에 저장
  • 숫자가 아닌 값, 혹은 빈 문자열, cancel 버튼을 누르면 질문 멈추기
  • 배열 요소의 함을 계산하고 리턴

이때 0은 유효한 숫자이므로 사용자가 0을 입력해도 질문이 멈추지 않아야 합니다. 아래 코드에서 +value 를 바로 적용하면 빈 문자열과 0을 구분할 수 없으므로 if 조건문 다음에 배열을 넣을 때 + 를 붙여주었습니다.

function sumInput() {
    let numbers = [];
    while (true) {
        let value = prompt("숫자를 입력해 주세요.", 0);
        if(value === "" || value === null || !isFinite(value)) break;
        numbers.push(+value);
    }
    let sum = 0;
    for (let number of numbers) {
        sum +- number;
    }
    return sum;
}
profile
Today I Learned

0개의 댓글