【问题标题】:JavaScript: Fast random indexing of object keysJavaScript:对象键的快速随机索引
【发布时间】:2019-01-10 18:46:59
【问题描述】:

我正在尝试从一个对象中随机选择一个随机属性,用作快速索引的字典。

考虑以下代码:

//Create test dictionary
var dict = {};
for(var i = 0; i < 10000; i++) {
  var num = Math.random() * 1000000 << 0;
  dict[num] = { Id: num };
}

//Fuzz
const NUM_RUNS = 1000;
var start = new Date();
for(var i = 0; i < NUM_RUNS; i++)
  getRandom(dict);
var end = new Date();

var runTime = (end.getTime() - start.getTime()) / 1000;
var timePerCall = (runTime / NUM_RUNS) * Math.pow(10,9);
console.log('Total Calls: ' + NUM_RUNS);
console.log('Total Runtime: ' + runTime + ' seconds');
console.log('Time Per Call: ' + timePerCall + ' nanoseconds');



function getRandom(dict) {
  var keys = Object.keys(dict);
  var index = keys[Math.random() * keys.length << 0];
  return dict[index];
}

如您所见,使用Object.keys() 非常昂贵,尤其是随着字典的增长。

我正在寻找一种最佳方式来实现随机选择字典中的元素。当然,字典中有 10000 多个元素是一个极端的情况,但我仍然希望能够处理它。

【问题讨论】:

    标签: javascript optimization


    【解决方案1】:

    如果缓存Object.keys 数组不可行,您可以使用Proxy 维护自己的副本:

    function generateKeyTracker (keysPropertyName) {
      const set = new Set();
      function defineProperty (target, property, descriptor) {
        target[property] = descriptor.value;
    
        if (set.has(property)) return true;
    
        set.add(property);
        target[keysPropertyName].push(property);
        return true;
      }
      function deleteProperty (target, property) {
        delete target[property];
        
        if (!set.delete(property)) return true;
    
        target[keysPropertyName] = target[keysPropertyName].filter(key => key !== property);
        return true;
      }
      return {defineProperty, deleteProperty};
    }
    
    //Create test dictionary
    var dict = new Proxy(
      Object.defineProperty({}, '__keys', {
        configurable: true,
        enumerable: false,
        writable: true,
        value: []
      }),
      generateKeyTracker('__keys')
    );
    
    for(var i = 0; i < 1e4; i++) {
      var num = Math.random() * 1e6 << 0;
      dict[num] = { Id: num };
    }
    
    //Fuzz
    const NUM_RUNS = 1e6;
    var start = performance.now();
    for(var i = 0; i < NUM_RUNS; i++)
      getRandom(dict);
    var end = performance.now();
    
    var runTime = end - start;
    var timePerCall = (runTime / NUM_RUNS);
    console.log(`Total Calls: ${NUM_RUNS}`);
    console.log(`Total Runtime: ${runTime} ms`);
    console.log(`Time Per Call: ${timePerCall * 1e6} ns`);
    
    function getRandom(dict) {
      var index = Math.random() * dict.__keys.length << 0;
      return dict[dict.__keys[index]];
    }

    这使用property creationdeletion 上的陷阱来跟踪dict 的属性键,这些键存储在non-enumerable 属性dict.__keys 中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-23
      • 2021-03-29
      • 1970-01-01
      • 2018-08-13
      • 2012-01-07
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多