[javascript] 2차원 배열과 다차원 배열 그리고 중첩 배열

자바스크립트는 내장된 데이터 타입으로 다차원 배열을 제공하지 않습니다. 

모든 배열은 1차원 배열입니다. 

자바스크립트에서는 모든 것이 객체이기 때문에, 배열의 각 요소를 다시 배열로 정의해 중첩하는 식으로 다차원 배열을 구현하게 됩니다.

배열 안에 다시 배열이 들어있는 경우 중첩 배열이 되고, 2차원 배열은 배열 안에 배열이 1번만 더 나오는 경우가 됩니다.

배열 안의 배열 요소에 대한 접근은

Array[1][2];

와 같이 사용합니다.

최외곽 배열부터 안쪽 배열로 단계를 내려가면서 인덱스 위치를 찾게 됩니다.

자바스크립트에서 3차원 이상의 배열은 거의 사용하지 않습니다.

중첩 배열 형태이기 때문에, 다차원이 되면 배열 탐색 속도가 느려지기도 하고, 언어적인 특성상 배열 요소 자체가 객체이기 때문에 대량의 데이터 처리에 불리해서 권장하지 않고 있기도 합니다.


!주의할 점

다른 언어에서는 Array[1][2] 와 Array[1,2] 의 의미가 다르고, 배열의 정의 및 데이터 입력 방법이 다르지만, 자바스크립트에서는 중첩배열 1가지만 있기 때문에 Array[1][2] 와 같이 사용하는 것만 가능합니다. 일부 메서드에서 비록 [1,2]와 같은 사용이 허용되기는 하지만, 어디까지나 사용상의 편의를 위해 제공되는 것이지 다른 언어의 2차원 배열과는 의미가 다른 것입니다.

let dolls = [['라이언',5], ['어피치',3], ['콘',2], ['무지',3], ['프로도',3]];
console.table(dolls);
console.log(dolls[0][1]); // 5 반환


!console.table()

배열로 된 데이터를 테이블로 예쁘게 정리해서 콘솔 화면에 뿌려주는 표준 콘솔 메서드입니다.

최신 웹브라우저에서는 모두 지원되는 기능으로 콘솔을 이용해 배열 데이터 내용을 파악할 때 편리합니다.

다차원 배열, 객체 배열까지 테이블 형태로 예쁘게 표시를 해줍니다.


중첩 배열의 요소 추가

자바스크립트의 배열 요소 추가 메서드를 사용해 아래와 같이 다양한 방법으로 배열 요소를 추가할 수 있습니다.

dolls.push(['브라운', 3]); // 상위 배열 끝에 추가
dolls.unshift(['펭수', 1]); // 상위 배열 맨 앞에 추가
dolls.splice(3, 0, ['네오', 3]); // 상위 배열 네번째 요소 앞에 추가

중첩 배열의 요소 삭제

배열 요소 추가와 쌍을 이루는 삭제 메서드를 이용해 중첩 배열 요소를 삭제할 수 있습니다.

dolls.pop(); // 상위 배열 맨 끝 요소 삭제
dolls.shift(); // 상위 배열 맨 앞 요소 삭제
dolls.splice(2,2); // 상위 배열 3번째 요소부터 2개를 삭제

중첩 배열의 순환

중첩 배열을 순환해 내부 배열 요소(컬럼)를 추가하거나 변경할 수 있습니다.

중첩 배열의 순환시 배열 요소를 제어하거나 추가/삭제를 할 수 있습니다.

단, 배열 순환을 하면서 상위 배열의 요소를 삭제하는 것은 예상치 못한 결과를 가져올 수 있으므로 주의해야 합니다.

//하위 배열에 성별 요소를 추가dolls2.forEach(doll=>{    doll[2] = doll[0] == '어피치' ? 'female' : 'male'; // 내부 배열에 성별 요소를 추가});    console.table(dolls2);    dolls2.forEach(function(doll, idx){    doll.pop();});
console.table(dolls2);

두번째 배열 순환을 아래와 같이 바꿔서 조건에 맞는 상위 배열 요소까지 함께 삭제하는 경우

//인자로 배열 인덱스를 같이 넘겨 조건에 맞으면 해당 상위 요소를 삭제 가능
dolls2.forEach(function(doll, idx){
  doll.pop();    //실행에는 아무런 문제가 없지만, 이런 방식으로 상위 배열의 요소를 삭제하는 것은 예상치 못한 결과를 발생시킵니다.
  if(doll[1] > 3){dolls2.splice(idx,1);
} // age가 3보다 크면 해당 하위 배열을 삭제});
console.table(dolls2);

예상과는 다른 이런 이상한 결과를 얻게 됩니다.

하위 배열의 마지막 요소(성별)를 삭제하고, 하위 배열의 2번째 요소(age)가 3보다 큰 경우 해당 요소를 삭제하는 간단한 조건 처리입니다.

예상대로라면 하위 배열의 2번째 요소가 모두 삭제되고, 상위 배열의 첫번째 요소인 '라이언' 배열이 삭제되어야 합니다.

하지만 여전히 하위 배열의 성별 요소가 남아있는 배열이 존재합니다.

배열을 순환하면서 첫번째 요소의 성별 요소를 삭제하고, age가 3보다 크므로 첫번째 요소를 삭제합니다.

두번째 요소를 순환할 때 인자로 넘어가는 idx는 1입니다. 

그러나, 첫번째 요소가 삭제되었기 때문에 2번째 요소는 첫번째 요소가 되었고, 인덱스 1인 2번째 요소는 원본 배열에서는 3번째 요소였던 '["콘", 2, "male"]' 이 됩니다.

즉, 원본에서 2번째 요소였던 '["어피치", 3, "female"]' 요소는 조건절 처리 없이 그냥 지나치게 됩니다.

따라서 하위 배열의 3번째 요소인 성별이 '어피치' 에서는 삭제되지 않고 남게 됩니다.

하위 배열과, 상위 배열 요소를 한꺼번에 조작하는 경우 이런 논리상의 오류로 인해 전혀 원하지 않는 결과가 나올 수 있습니다.

따라서 중첩 배열을 수정하거나 조작할 경우에는 한가지만 하거나, 삭제와 같은 조작은 피하는 것이 좋습니다.

비정형 중첩 배열

자바스크립트는 자유도가 높기 때문에 2차원 중첩 배열의 내부 배열 요소 갯수가 일치하지 않는 배열을 생성할 수 있습니다.

let dolls3 = [['라이언',5], ['어피치',3], ['콘',2], ['무지',3], ['프로도',3]];
dolls3.forEach(doll=>{
  if(doll[1] > 3){
    doll.pop();
  } // age가 3보다 크면 마지막 요소(age)를 삭제});
  console.table(dolls3);
  dolls3.forEach(doll=>{
    console.log(doll[0] + ' 은/는 '+doll[1] + '살 입니다.');// 첫 요소에서 undefined 반환
  }
);

중첩 배열을 생성해 사용할 경우 비정형 배열을 사용하는 것이 가능하더라도 가능하면 하위 배열 요소의 갯수를 맞춰 사용하는 것을 권장합니다.

비정형 배열이 될 경우, 배열 요소의 유무를 체크하는 추가의 조건절이 있어야 하기 때문에 초기값, 또는 빈 문자열 같은 기본 값이 있도록 해서 간결하고 신뢰할 수 있는 코드를 만드는 것이 좋습니다.