JavaScript:对象键的快速随机索引

标签 javascript optimization

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

考虑以下代码:

//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 多个元素是一种极端的边缘情况,但我仍然希望能够处理它。

最佳答案

如果缓存 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 creation 上的陷阱和 deletion跟踪 dict 的属性键,这些键存储在 non-enumerable 中属性dict.__keys

关于JavaScript:对象键的快速随机索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51663061/

相关文章:

javascript - 如何使用 lodash 创建嵌套过滤器

Mysql慢查询: INNER JOIN + ORDER BY causes filesort

javascript - 将一组对象加入一个对象?

javascript - 如何将接受/拒绝所有建议添加到 Google 文档附加组件

javascript - 需要帮助重构一个简单的 jquery 动画脚本

javascript - 如何检查 value 是否是最后一个 csv 条目?

c++ - 通过 2d 数组 C++ 传播的最快方法

optimization - 如何将数字的最后3位数字转换为0

c - 数组指针及相关表达式求值

c++ - 查看固定长度数组之间有多少字节相等的最快方法