programmers에 새로 올라온 문제(햄버거 만들기)를 javascript로 시간 복잡도 생각 안 하고 흐름대로 풀다가 배열을 비교하는 부분에서 오류가 났었다. 따라서 javascript는 python과 달리 배열을 비교하는 것이 다르구나!!
해서 공부할 겸 정리할 겸 포스트를 올려본다.
일단, python과 js로 배열을 비교하는 것을 살펴보자!
arr1 = [1, 2, 3]
arr2 = [1, 2, 3]
print(arr1 == arr2) // True
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1 === arr2) // false
js
에서는 false가 나왔다. 혹시?? 하는 마음에 ==
operator를 사용해보았다.
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1 == arr2) // false
이것도 false
가 나온다. python으로 알고리즘 풀이를 하던 나에게는 좀 이질감이 있었지만 한참 고민하다가 javascript에서 배열도 object로서 참조값으로 비교하는 것이 아닐까?
라는 의문을 가지게 되었는데 찾아보니 결과적으로 맞추었다!!🥳
참조값으로 객체를 비교한다고??? 라는 의문이 든다면 아래 class예제를 보자
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
printInfo() {
console.log(`name: ${this.name}\tage: ${this.age}`);
}
}
const tom = new Person("Tom", 22);
const tom1 = new Person("Tom", 22);
console.log(tom1 === tom1); // false
tom
과 tom1
은 name, age
가 같지만 tom과 tom1은 같지않다.
클래스를 공부해봤다면 같은 클래스(여기서 Person)로부터 만들어진 instance는 각각 고유한 객체로서 다른 주소값(참조값)을 가지기 때문
이다.
📒 따라서 javascript는 Array class로 부터 array를 만듬으로 같은 요소를 가진 배열이라 해도 참조값이 달라 다른 배열이라고 판단한다.
여기서 저기서 찾아보고 혼자 생각해보고 취합한 결과 총 3가지
방법을 모아봤다.
1, 2, 3은 javascript에서 string을 비교하는 원리를 이용
한 것이다.
function isSame(arr1, arr2) {
if (arr1.length !== arr2.length) {
throw new Error("length is different!!");
} else if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
throw new Error("both of object should have array type!!");
}
return JSON.stringify(arr1) === JSON.stringify(arr2);
}
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = [2, 3, 4];
console.log(isSame(arr1, arr2)); // true
console.log(isSame(arr1, arr3)); // false
function isSame(arr1, arr2) {
...// // 👈 handle error can see above JSON.stringify code
return arr1.toString() === arr2.toString();
}
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = [2, 3, 4];
console.log(isSame(arr1, arr2)); // true
console.log(isSame(arr1, arr3)); // false
function isSame(arr1, arr2) {
...// // 👈 handle error can see above JSON.stringify code
let result = true;
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
result = false;
break;
}
}
return result;
}
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = [2, 3, 4];
console.log(isSame(arr1, arr2)); // true
console.log(isSame(arr1, arr3)); // false
이것은 어느 것을 쓰는게 제일 빠를까 생각이 들어서 코드를 짜보게 되었다. 현대는 메모리는 충분하여 메모리 효율보다는 시간 효율을 중시한다는 얘기를 얼핏 들었다. 여러방법을 알아도 빠르면서 나에게 맞는 방법을 찾고자 한 번 테스트 해 봤다.
for-stat, stringify, toString
모두 O(n)의 시간 복잡도를 가지므로 거기서 거기라고 생각했지만, for 구문에 break(값을 비교하다가 중간에 틀리면 바로 루프를 중단하면 되므로)
를 건다면 다른 것보다 훨씬 빠를 수 있다고 생각했다.
일단, 전체 코드는 아래와 같다.
test code
function isSuitable(arr1, arr2) {
let result = true;
if (arr1.length !== arr2.length) {
result = false;
throw new Error("length is different!!");
} else if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
result = false;
throw new Error("both of object should have array type!!");
}
return result;
}
function isSameJSON(arr1, arr2) {
if (isSuitable(arr1, arr2)) {
return JSON.stringify(arr1) === JSON.stringify(arr2);
}
return console.error("unexpected error!!");
}
function isSameToString(arr1, arr2) {
if (isSuitable(arr1, arr2)) {
return arr1.toString() === arr2.toString();
}
return console.error("unexpected error!!");
}
function isSameFor(arr1, arr2) {
let result = true;
if (isSuitable(arr1, arr2)) {
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
result = false;
break;
}
}
return result;
}
return console.error("unexpected error!!");
}
function createArray(arrayLength, maxNumber) {
const arr = [];
for (let i = 0; i < arrayLength; i++) {
arr.push(Math.floor(Math.random() * maxNumber));
}
return arr;
}
const LENGTH = 100000000;
const MAX_NUMBER = 4;
const arr1 = (arr2 = createArray(LENGTH, MAX_NUMBER));
const arr3 = createArray(LENGTH, MAX_NUMBER);
console.time("JSON.stringify");
isSameJSON(arr1, arr2);
isSameJSON(arr1, arr3);
console.timeEnd("JSON.stringify");
console.time("toString");
isSameToString(arr1, arr2);
isSameToString(arr1, arr3);
console.timeEnd("toString");
console.time("for same array");
isSameFor(arr1, arr2);
console.timeEnd("for same array");
console.time("for not same array");
isSameFor(arr1, arr3);
console.timeEnd("for not same array");
배열의 길이 1억
으로 스스로 테스트를 해본 결과 for-stat > JSON.stringify > toString
순으로 빨랐다. 그냥 for-stat가 압도적으로 빨랐다...
ㄷㄷ😳
테스트를 정확히 할 줄 몰라 정확하게 테스트를 한 지는 모르지만, 스스로 해 본 결과 for구문을 이용하는 것이 가장 빠름을 보았다. 사실상 toString, stringify를 쓰는 것이 덜 수고스럽지만 많은 데이터를 다룰 때는 for구문을 이용하고 데이터가 적다면 stringify를 이용하여 비교를 해야겠다. 문득 든 생각으로 스스로 테스트 코드??를 짰는데 값진 것을 얻어가는 느낌이라 기분이 좋다!!😁