자바 스크립트 세트 대 어레이 성능
세트가 자바 스크립트에 상대적으로 새롭기 때문일 수 있지만 StackO 또는 다른 곳에서 자바 스크립트에서 둘 사이의 성능 차이에 대해 설명하는 기사를 찾을 수 없었습니다. 그렇다면 성능 측면에서 둘 사이의 차이점은 무엇입니까? 특히 제거, 추가 및 반복과 관련하여.
좋아, 배열과 집합에서 요소를 추가, 반복 및 제거하는 것을 테스트했습니다. 나는 10,000 개의 요소를 사용하는 "작은"테스트와 100,000 개의 요소를 사용하는 "큰"테스트를 실행했습니다. 결과는 다음과 같습니다.
컬렉션에 요소 추가
추가되는 요소의 수에 관계없이 .push
배열 방법은 .add
set 방법 보다 약 4 배 빠른 것 같습니다 .
컬렉션의 요소 반복 및 수정
테스트의이 부분에서는 for
루프를 사용하여 배열 for of
을 반복 하고 루프를 사용하여 세트를 반복했습니다. 다시 말하지만 어레이를 반복하는 것이 더 빨랐습니다. 이번에는 "작은"테스트에서는 두 배, "큰"테스트에서는 거의 4 배 더 오래 걸리므로 기하 급수적으로 보일 것입니다.
컬렉션에서 요소 제거
이제 이것이 흥미로워지는 곳입니다. 나는 for
루프 의 조합을 .splice
사용 for of
하고 배열에서 일부 요소 .delete
를 제거하고 세트에서 일부 요소를 사용 하고 제거했습니다. "작은"테스트의 경우 세트에서 항목을 제거하는 것이 약 3 배 더 빨랐지만 (2.6ms 대 7.1ms) "대형"테스트의 경우에는 항목을 배열에서 제거하는 데 1955.1ms가 소요되었지만 세트에서 제거하는 데 83.6ms가 걸렸습니다.
결론
10k 요소에서 두 테스트 모두 비슷한 시간 (배열 : 16.6ms, 세트 : 20.7ms)을 실행했지만 100k 요소를 처리 할 때 세트가 확실한 승자였습니다 (배열 : 1974.8ms, 세트 : 83.6ms). 조작. 그렇지 않으면 어레이가 더 빨랐습니다. 그 이유를 정확히 말할 수 없었습니다.
배열이 생성되고 채워진 다음 일부 요소가 제거되는 세트로 변환 된 다음 세트가 배열로 다시 변환되는 하이브리드 시나리오를 가지고 놀았습니다. 이렇게하면 배열에서 요소를 제거하는 것보다 훨씬 더 나은 성능을 제공 할 수 있지만 세트로 /에서 전송하는 데 필요한 추가 처리 시간이 세트 대신 배열을 채우는 이점보다 큽니다. 결국 세트 만 처리하는 것이 더 빠릅니다. 그럼에도 불구하고, 중복이없는 일부 빅 데이터에 대한 데이터 수집으로 어레이를 사용하기로 선택하면 하나에서 많은 요소를 제거해야하는 경우 성능 측면에서 유리할 수 있다는 것은 흥미로운 아이디어입니다. 배열을 집합으로 변환하고 제거 작업을 수행 한 다음 집합을 배열로 다시 변환합니다.
어레이 코드 :
var timer = function(name) {
var start = new Date();
return {
stop: function() {
var end = new Date();
var time = end.getTime() - start.getTime();
console.log('Timer:', name, 'finished in', time, 'ms');
}
}
};
var getRandom = function(min, max) {
return Math.random() * (max - min) + min;
};
var lastNames = ['SMITH', 'JOHNSON', 'WILLIAMS', 'JONES', 'BROWN', 'DAVIS', 'MILLER', 'WILSON', 'MOORE', 'TAYLOR', 'ANDERSON', 'THOMAS'];
var genLastName = function() {
var index = Math.round(getRandom(0, lastNames.length - 1));
return lastNames[index];
};
var sex = ["Male", "Female"];
var genSex = function() {
var index = Math.round(getRandom(0, sex.length - 1));
return sex[index];
};
var Person = function() {
this.name = genLastName();
this.age = Math.round(getRandom(0, 100))
this.sex = "Male"
};
var genPersons = function() {
for (var i = 0; i < 100000; i++)
personArray.push(new Person());
};
var changeSex = function() {
for (var i = 0; i < personArray.length; i++) {
personArray[i].sex = genSex();
}
};
var deleteMale = function() {
for (var i = 0; i < personArray.length; i++) {
if (personArray[i].sex === "Male") {
personArray.splice(i, 1)
i--
}
}
};
var t = timer("Array");
var personArray = [];
genPersons();
changeSex();
deleteMale();
t.stop();
console.log("Done! There are " + personArray.length + " persons.")
코드 설정 :
var timer = function(name) {
var start = new Date();
return {
stop: function() {
var end = new Date();
var time = end.getTime() - start.getTime();
console.log('Timer:', name, 'finished in', time, 'ms');
}
}
};
var getRandom = function (min, max) {
return Math.random() * (max - min) + min;
};
var lastNames = ['SMITH','JOHNSON','WILLIAMS','JONES','BROWN','DAVIS','MILLER','WILSON','MOORE','TAYLOR','ANDERSON','THOMAS'];
var genLastName = function() {
var index = Math.round(getRandom(0, lastNames.length - 1));
return lastNames[index];
};
var sex = ["Male", "Female"];
var genSex = function() {
var index = Math.round(getRandom(0, sex.length - 1));
return sex[index];
};
var Person = function() {
this.name = genLastName();
this.age = Math.round(getRandom(0,100))
this.sex = "Male"
};
var genPersons = function() {
for (var i = 0; i < 100000; i++)
personSet.add(new Person());
};
var changeSex = function() {
for (var key of personSet) {
key.sex = genSex();
}
};
var deleteMale = function() {
for (var key of personSet) {
if (key.sex === "Male") {
personSet.delete(key)
}
}
};
var t = timer("Set");
var personSet = new Set();
genPersons();
changeSex();
deleteMale();
t.stop();
console.log("Done! There are " + personSet.size + " persons.")
관찰 :
- 집합 작업은 실행 스트림 내에서 스냅 샷으로 이해할 수 있습니다.
- 우리는 확실한 대체물이 아닙니다.
- Set 클래스 의 요소 에는 액세스 가능한 인덱스가 없습니다.
- Set 클래스 는 Array 클래스 보완으로, 기본 추가, 삭제, 검사 및 반복 작업을 적용 할 컬렉션을 저장해야하는 시나리오에서 유용합니다.
성능 테스트를 공유합니다. 콘솔을 열고 아래 코드를 복사하여 붙여 넣으십시오.
어레이 만들기 (125000)
var n = 125000;
var arr = Array.apply( null, Array( n ) ).map( ( x, i ) => i );
console.info( arr.length ); // 125000
1. 색인 찾기
Set의 has 메소드를 Array indexOf와 비교했습니다.
배열 / 같이 IndexOf (0.281ms) | 세트 / 가 (0.053ms)을
// Helpers
var checkArr = ( arr, item ) => arr.indexOf( item ) !== -1;
var checkSet = ( set, item ) => set.has( item );
// Vars
var set, result;
console.time( 'timeTest' );
result = checkArr( arr, 123123 );
console.timeEnd( 'timeTest' );
set = new Set( arr );
console.time( 'timeTest' );
checkSet( set, 123123 );
console.timeEnd( 'timeTest' );
2. 새 요소 추가
Set 및 Array 개체의 추가 및 푸시 메서드를 각각 비교합니다.
Array/push (1.612ms) | Set/add (0.006ms)
console.time( 'timeTest' );
arr.push( n + 1 );
console.timeEnd( 'timeTest' );
set = new Set( arr );
console.time( 'timeTest' );
set.add( n + 1 );
console.timeEnd( 'timeTest' );
console.info( arr.length ); // 125001
console.info( set.size ); // 125001
3. Deleting an element
When deleting elements, we have to keep in mind that Array and Set do not start under equal conditions. Array does not have a native method, so an external function is necessary.
Array/deleteFromArr (0.356ms) | Set/remove (0.019ms)
var deleteFromArr = ( arr, item ) => {
var i = arr.indexOf( item );
i !== -1 && arr.splice( i, 1 );
};
console.time( 'timeTest' );
deleteFromArr( arr, 123123 );
console.timeEnd( 'timeTest' );
set = new Set( arr );
console.time( 'timeTest' );
set.delete( 123123 );
console.timeEnd( 'timeTest' );
Read the full article here
My observation is that a Set is always better with two pitfalls for large arrays in mind :
a) The creation of Sets from Arrays must be done in a for
loop with a precached length.
slow (e.g. 18ms) new Set(largeArray)
fast (e.g. 6ms) const SET = new Set(); const L = largeArray.length; for(var i = 0; i<L; i++) { SET.add(largeArray[i]) }
b) Iterating could be done in the same way because it is also faster than a for of
loop ...
See https://jsfiddle.net/0j2gkae7/5/
for a real life comparison to difference()
, intersection()
, union()
and uniq()
( + their iteratee companions etc.) with 40.000 elements
I recently ran this test and found that Set much outperformed an Array of 1000 items (around 10x the operations could happen in the same timeframe). And depending on the browser either beat or lost to Object.hasOwnProperty in a like for like test.
Both Set and Object have their "has" method performing in what seems to be amortized to O(1), but depending on the browser's implementation a single operation could take longer or faster.
https://jsperf.com/set-has-vs-object-hasownproperty-vs-array-includes/1 In case you want to run your own tests with different browsers/environments.
console.time("set")
var s = new Set()
for(var i = 0; i < 10000; i++)
s.add(Math.random())
s.forEach(function(e){
s.delete(e)
})
console.timeEnd("set")
console.time("array")
var s = new Array()
for(var i = 0; i < 10000; i++)
s.push(Math.random())
s.forEach(function(e,i){
s.splice(i)
})
console.timeEnd("array")
Those three operations on 10K items gave me:
set: 7.787ms
array: 2.388ms
참고URL : https://stackoverflow.com/questions/39007637/javascript-set-vs-array-performance
'Nice programing' 카테고리의 다른 글
JTable, 사용자 열 드래그 비활성화 (0) | 2020.11.27 |
---|---|
pkl 파일의 압축을 푸는 방법은 무엇입니까? (0) | 2020.11.27 |
새로운 Django 메시지 프레임 워크의 메시지에 HTML을 어떻게 출력합니까? (0) | 2020.11.27 |
핵심 데이터를 미리 채우는 방법이 있습니까? (0) | 2020.11.27 |
urllib2의 시간 초과 처리? (0) | 2020.11.27 |