희소 배열이라고 들어보았나? 학부생 때 교양 혹은 전공으로 선형대수를 배웠다면, 희소 행렬이라고는 들어보았을 것이다. 들었지만 아마 기억에는 없을 수도 있겠다. 행렬에 0이 비교적 많은 행렬을 희소 행렬이라고 부른다. 0이 많다는 것은 데이터가 없다는 것으로 볼 수 있다.
뭐 물론 프로그래밍을 하면서 배열에 0이 많다고 해서 희소 배열이라고 부르지는 않을 것이다.
희소 배열
아마 알고리즘 연습을 하는 사람들은 아래와 같이 배열의 개수를 초기화하는 코드를 작성 해본 사람이 있을 것이다.
let a = []
a.length = 30
인풋이던 아웃풋이던 30개로 고정되어야 하는 상황 같은 때 말이다. 위의 결과는 무엇일까? 아마도 위와 같은 코드를 작성해본 사람이라면 알 것이다.
empty가 30개 있다고 한다. 일단 난 희소 배열의 정의를 empty가 하나라도 있는 상황을 희소 배열이라고 부르겠다.희소 배열을 만드는 방법은 아래처럼 더 있다. delete를 사용 한다던가 일부러 초기화를 안 하는 경우다.
let a = [1, 2, , 4]
delete a[1]
empty?
그래 희소 배열이 존재 하는 것은 알았다. 그러면 왜 알아야 하는가? 이것이 궁금할 수도 있다.일단 하나만 집고 넘어가자 empty는 값도 아니고, 예약어도 아니다. 저장할 수도 없고, 읽을 수도 없다. 우리에게는 데이터가 없다는 표현으로 undefined가 있다.
하지만 empty와 undefined는 다르다! 자 아래 실험을 보자.
let a = [1, ,3]
a[0] = a[1]
분명 empty의 값을 갖고 있는 1번 인덱스에서 값을 가져와 0번 인덱스에 값을 삽입 하였으나, undefined가 되어버렸다.
이는 자바스크립의 배열 객체에서 1번 인덱스를 읽는 상황에서 undefined를 리턴 하였기 때문 이라 추측 된다.
empty vs undefined
empty는 배열 내에서만 존재하는 값이며, 읽는 순간 undefined로 결정이 된다. 둘의 값은 유사하지만, 반복문 에서는 꽤 다른 양상을 보인다.
let a = [, , undefined, undefined]
for( let i = 0; i < a.length; i++ ) {
console.log(`value of ${i} : ${a[i]}`)
/*
* value of 0 : undefined
* value of 1 : undefined
* value of 2 : undefined
* value of 3 : undefined
* */
}
for( const v of a ) {
console.log(`value: ${v}`)
/*
* value : undefined
* value : undefined
* value : undefined
* value : undefined
* */
}
for( const i in a ) {
console.log(`value of ${i} : ${a[i]}`)
/*
* value of 2 : undefined
* value of 3 : undefined
* */
}
a.forEach((v, i) => console.log(`value of ${i} : ${v}`))
/*
* value of 2 : undefined
* value of 3 : undefined
* */
위 처럼 두가지 부류로 구분이 된다.
empty까지 반복할 수 있는 length기반의 for문과 iterator 기반의 for of문
empty는 생략하는 Array.forEach와 in 연산자 기반의 for in문.
in연산자로 비교를 해보면 아래와 같이 재밌는 결과를 볼 수 있다.
let a = [, , undefined, undefined]
0 in a // false
1 in a // false
2 in a // true
3 in a // true
즉 empty의 정체는 키가 정의 되어있지 않은 배열의 인덱스이다. 뭐 물론 인덱스 자체가 키이기 때문에 모순이 되는 정의 이지만... in 연산자는 명시된 속성이 명시된 객체에 존재하면 true를 반환한다.
존재라는 단어가 해석의 여지가 있지만, undefined, null, false 등 falsy 값들에서는 true를 리턴하니, 키가 falsy인 경우만 false를 리턴한다고 추측해볼 수 있을 것이다.
결론적으로 하고 싶은 말은 이것이다. 희소 행렬을 만들지 말라는 것이다. 뭐 물론 Array.map, retuduce, forEach 처럼 Array 기본 함수나 for in을 쓰지 말라고 할 수 있지만, 그것보다는 희소 배열을 만들지 않는 것이 좀 더 올바른 방법이라 생각 된다.
댓글
댓글 쓰기