source

배열 vs.자바스크립트에서 객체 효율성

ittop 2023. 10. 4. 22:58
반응형

배열 vs.자바스크립트에서 객체 효율성

저는 수천 개의 물건을 가지고 있는 모델을 가지고 있습니다.ID가 있으면 저장하고 하나의 개체를 검색하는 가장 효율적인 방법이 무엇인지 궁금했습니다.ID는 긴 숫자입니다.

그래서 제가 생각하고 있던 두 가지 옵션입니다.옵션 1에서는 인덱스가 증가하는 단순 배열입니다. 옵션 2에서는 연관 배열이고 차이가 있다면 개체일 수도 있습니다.제 질문은 어떤 것이 더 효율적인가 하는 것입니다. 제가 주로 하나의 객체를 검색해야 할 때, 그리고 가끔은 그것들을 순환하고 분류해야 할 때 말이죠.

비연관 배열이 있는 옵션 1:

var a = [{id: 29938, name: 'name1'},
         {id: 32994, name: 'name1'}];
function getObject(id) {
    for (var i=0; i < a.length; i++) {
        if (a[i].id == id) 
            return a[i];
    }
}

연관 배열이 있는 옵션 2:

var a = [];  // maybe {} makes a difference?
a[29938] = {id: 29938, name: 'name1'};
a[32994] = {id: 32994, name: 'name1'};
function getObject(id) {
    return a[id];
}

업데이트:

, .var a = {};유일한 질문은 주어진 id를 가진 객체를 검색할 때 더 나은 성능을 발휘하는 것이 무엇인가 하는 것입니다. id가 키인 object 또는 배열입니다.

그리고 리스트를 여러번 정렬해야 한다면 답변이 달라질까요?

짧은 버전:어레이는 대부분 물체보다 빠릅니다.하지만 100% 정확한 해결책은 없습니다.

업데이트 2017 - 테스트 및 결과

var a1 = [{id: 29938, name: 'name1'}, {id: 32994, name: 'name1'}];

var a2 = [];
a2[29938] = {id: 29938, name: 'name1'};
a2[32994] = {id: 32994, name: 'name1'};

var o = {};
o['29938'] = {id: 29938, name: 'name1'};
o['32994'] = {id: 32994, name: 'name1'};

for (var f = 0; f < 2000; f++) {
    var newNo = Math.floor(Math.random()*60000+10000);
    if (!o[newNo.toString()]) o[newNo.toString()] = {id: newNo, name: 'test'};
    if (!a2[newNo]) a2[newNo] = {id: newNo, name: 'test' };
    a1.push({id: newNo, name: 'test'});
}

test setup test results

원본 게시물 - 설명

당신의 질문에 오해가 좀 있습니다.

자바스크립트에는 연관 배열이 없습니다.배열 및 개체만.

어레이는 다음과 같습니다.

var a1 = [1, 2, 3];
var a2 = ["a", "b", "c"];
var a3 = [];
a3[0] = "a";
a3[1] = "b";
a3[2] = "c";

이것도 배열입니다.

var a3 = [];
a3[29938] = "a";
a3[32994] = "b";

기본적으로 구멍이 뚫린 배열입니다. 모든 배열에는 연속적인 인덱싱이 있기 때문입니다.구멍이 없는 배열보다 느립니다.하지만 어레이를 수동으로 반복하는 것은 훨씬 더 느립니다(대부분).

개체:

var a3 = {};
a3[29938] = "a";
a3[32994] = "b";

다음은 세 가지 가능성에 대한 성능 테스트입니다.

Lookup Array vs Holey Array vs Object 성능 테스트

Smashing Magazine에서 다음 주제에 대한 훌륭한 읽기:빠른 메모리 효율적인 자바스크립트 작성

어레이와 객체는 매우 다르게 작동하기 때문에(적어도 그래야 하기 때문에) 성능 문제는 전혀 아닙니다.e를 갖습니다.0..n, 개체는 임의 키를 임의 값에 매핑합니다.특정 키를 제공하려면 개체만 선택할 수 있습니다.열쇠를 신경쓰지 않으면 배열이 됩니다.

배열에 임의(숫자) 키를 설정하려고 하면 해당 배열이 그 사이의 모든 인덱스를 채우게 되므로 실제로 성능이 저하됩니다.

> foo = [];
  []
> foo[100] = 'a';
  "a"
> foo
  [undefined, undefined, undefined, ..., "a"]

(배열에는 실제로 99가 포함되어 있지 않습니다.undefinedvalues, 하지만 어느 시점에서 배열을 [supposed] 반복하고 있으므로 이렇게 동작합니다.)

두 가지 옵션에 대한 문헌은 다음과 같이 어떻게 사용될 수 있는지를 매우 명확히 해야 합니다.

var arr = ['foo', 'bar', 'baz'];     // no keys, not even the option for it
var obj = { foo : 'bar', baz : 42 }; // associative by its very nature

ES6의 경우 가장 성능이 뛰어난 방법은 지도를 사용하는 것입니다.

var myMap = new Map();

myMap.set(1, 'myVal');
myMap.set(2, { catName: 'Meow', age: 3 });

myMap.get(1);
myMap.get(2);

ES6 기능은 현재 심(https://github.com/es-shims/es6-shim) 을 사용하여 사용할 수 있습니다.

브라우저와 시나리오에 따라 성능이 달라집니다.다가 한 .Map성능이 가장 우수합니다: https://jsperf.com/es6-map-vs-object-properties/2


참조 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

NodeJS에서 당신이 알고 있는 것은ID은 , 느립니다.object[ID].

const uniqueString = require('unique-string');
const obj = {};
const arr = [];
var seeking;

//create data
for(var i=0;i<1000000;i++){
  var getUnique = `${uniqueString()}`;
  if(i===888555) seeking = getUnique;
  arr.push(getUnique);
  obj[getUnique] = true;
}

//retrieve item from array
console.time('arrTimer');
for(var x=0;x<arr.length;x++){
  if(arr[x]===seeking){
    console.log('Array result:');
    console.timeEnd('arrTimer');
    break;
  }
}

//retrieve item from object
console.time('objTimer');
var hasKey = !!obj[seeking];
console.log('Object result:');
console.timeEnd('objTimer');

결과는 다음과 같습니다.

Array result:
arrTimer: 12.857ms
Object result:
objTimer: 0.051ms

탐색 ID가 배열/객체의 첫 번째 ID인 경우에도:

Array result:
arrTimer: 2.975ms
Object result:
objTimer: 0.068ms

나는 이것을 다음 차원으로 가져가려고 했습니다. 말 그대로.

x축과 y축의 길이가 항상 동일한 2차원 배열이 주어지면 다음과 같은 작업을 수행하는 것이 더 빠릅니다.

a) 2차원 배열을 작성하고 첫 번째 인덱스를 검색한 다음 두 번째 인덱스를 검색하여 셀을 찾습니다.

var arr=[][]    
var cell=[x][y]    

아니면

b) x 및 y 좌표의 문자열 표현으로 객체를 만든 다음 해당 객체를 단일 조회합니다.

var obj={}    
var cell = obj['x,y']    

:
개체에 대한 속성 조회보다 배열에 대한 숫자 인덱스 조회를 두 번 수행하는 것이 훨씬 빠른 것으로 나타났습니다.

결과:

http://jsperf.com/arr-vs-obj-lookup-2

용도에 따라 다릅니다.Lookup Objects의 경우가 매우 빠릅니다.

배열 및 객체 조회의 성능을 테스트하기 위한 Plunker 예제가 있습니다.

https://plnkr.co/edit/n2expPWVmsdR3zmXvX4C?p=preview

5.000 길이의 배열 컬렉션에서 5.000개의 항목을 검색하면 다음을 이어받습니다.3000

그러나 개체에서 5.000개의 항목을 조회하면 5.000개의 속성이 있습니다.2아니면3

또한 오브젝트 트리를 만드는 것은 큰 차이가 없습니다.

x개 품목으로 한정된 이벤트 소스에서 살아있는 촛대를 보관해야 하는 상황에 직면한 비슷한 문제가 있었습니다.각 촛불의 타임스탬프가 키 역할을 하고 촛불 자체가 값 역할을 하는 객체에 저장할 수 있었습니다.또 다른 가능성은 각각의 물건이 촛불 자체인 배열로 보관할 수 있다는 것이었습니다.라이브 캔들에 대한 한 가지 문제점은 최신 업데이트가 가장 최근의 데이터를 보관하는 동일한 타임스탬프에 업데이트를 계속 전송하기 때문에 기존 항목을 업데이트하거나 새 항목을 추가하는 것입니다.여기 세 가지 가능성을 모두 결합하려는 멋진 벤치마크가 있습니다.아래 솔루션의 어레이는 평균 4배 이상 빠릅니다.자유롭게 놀아요.

"use strict";

const EventEmitter = require("events");
let candleEmitter = new EventEmitter();

//Change this to set how fast the setInterval should run
const frequency = 1;

setInterval(() => {
    // Take the current timestamp and round it down to the nearest second
    let time = Math.floor(Date.now() / 1000) * 1000;
    let open = Math.random();
    let high = Math.random();
    let low = Math.random();
    let close = Math.random();
    let baseVolume = Math.random();
    let quoteVolume = Math.random();

    //Clear the console everytime before printing fresh values
    console.clear()

    candleEmitter.emit("candle", {
        symbol: "ABC:DEF",
        time: time,
        open: open,
        high: high,
        low: low,
        close: close,
        baseVolume: baseVolume,
        quoteVolume: quoteVolume
    });



}, frequency)

// Test 1 would involve storing the candle in an object
candleEmitter.on('candle', storeAsObject)

// Test 2 would involve storing the candle in an array
candleEmitter.on('candle', storeAsArray)

//Container for the object version of candles
let objectOhlc = {}

//Container for the array version of candles
let arrayOhlc = {}

//Store a max 30 candles and delete older ones
let limit = 30

function storeAsObject(candle) {

    //measure the start time in nanoseconds
    const hrtime1 = process.hrtime()
    const start = hrtime1[0] * 1e9 + hrtime1[1]

    const { symbol, time } = candle;

    // Create the object structure to store the current symbol
    if (typeof objectOhlc[symbol] === 'undefined') objectOhlc[symbol] = {}

    // The timestamp of the latest candle is used as key with the pair to store this symbol
    objectOhlc[symbol][time] = candle;

    // Remove entries if we exceed the limit
    const keys = Object.keys(objectOhlc[symbol]);
    if (keys.length > limit) {
        for (let i = 0; i < (keys.length - limit); i++) {
            delete objectOhlc[symbol][keys[i]];
        }
    }

    //measure the end time in nano seocnds
    const hrtime2 = process.hrtime()
    const end = hrtime2[0] * 1e9 + hrtime2[1]

    console.log("Storing as objects", end - start, Object.keys(objectOhlc[symbol]).length)
}

function storeAsArray(candle) {

    //measure the start time in nanoseconds
    const hrtime1 = process.hrtime()
    const start = hrtime1[0] * 1e9 + hrtime1[1]

    const { symbol, time } = candle;
    if (typeof arrayOhlc[symbol] === 'undefined') arrayOhlc[symbol] = []

    //Get the bunch of candles currently stored
    const candles = arrayOhlc[symbol];

    //Get the last candle if available
    const lastCandle = candles[candles.length - 1] || {};

    // Add a new entry for the newly arrived candle if it has a different timestamp from the latest one we storeds
    if (time !== lastCandle.time) {
        candles.push(candle);
    }

    //If our newly arrived candle has the same timestamp as the last stored candle, update the last stored candle
    else {
        candles[candles.length - 1] = candle
    }

    if (candles.length > limit) {
        candles.splice(0, candles.length - limit);
    }

    //measure the end time in nano seocnds
    const hrtime2 = process.hrtime()
    const end = hrtime2[0] * 1e9 + hrtime2[1]


    console.log("Storing as array", end - start, arrayOhlc[symbol].length)
}

결론 10은 여기서 한계입니다.

Storing as objects 4183 nanoseconds 10
Storing as array 373 nanoseconds 10
  1. 인덱싱된 필드(숫자 키가 있는 필드)는 개체 내부에 신성 배열로 저장됩니다.따라서 조회시간은 O(1)입니다.

  2. 룩업 배열의 경우에도 동일하게 O(1)입니다.

  3. 객체 배열을 반복하고 해당 ID를 제공된 개체와 비교하여 테스트하는 것이 O(n) 연산입니다.

언급URL : https://stackoverflow.com/questions/17295056/array-vs-object-efficiency-in-javascript

반응형