有没有适合此问题的数据结构或优化方法?

时间:2019-07-23 12:35:50

标签: javascript performance dictionary optimization data-structures

我有一个Node.JS服务器,并且其中有一个字典(哈希/映射)(键是一个数字,值-数组)。字典的每个元素都是ID(字符串)的数组,并且包含许多元素。数组的每个元素在数组中都是唯一的。例如:

let map = {2333:['id1', 'id2', 'id3', 'id4'], 1234:['id3', 'id4', 'id5'], 123213:['id4', 'id5', 'id77']}

服务器有一些查询,这些查询将新元素添加到数组或字典中。这种情况确实经常发生。还有另一种查询,以字典中的几个键为参数。我需要遍历该集合,通过集合中的键找到字典中的所有数组,并计算每个ID出现的次数。这是我简单的解决方案:

let queryArray = [1234, 123213];
let result = {};//Resulting hash of ID's occurrences
for(let i=0; i<queryArray.length; i++){
    let key = queryArray[i];
    if(!key) continue;
    let array = map[key];
    for(let j=0; j<array.length; j++){
        let id = array[j];
        if(!result[id]) result[id] = 0;
        result[id]++;
    }
 }
//result = {'id3':1, 'id4':2, 'id5':2, 'id77':1};

此操作实际上经常在服务器上发生,我需要以某种方式对其进行优化。你有什么想法?答案的编程语言无关紧要。

2 个答案:

答案 0 :(得分:1)

您可以仅为计数查询创建元数据对象。
如果您负担得起重复拥有的数据大小,则可以应用此方法。

let map = {
  2333:['id1', 'id2', 'id3', 'id4'],
  1234:['id3', 'id4', 'id5'],
  123213:['id4', 'id5', 'id77']
}
let counts = {
   2333: { id1: 1, id2: 1, id3: 1, id4: 1 },
   1234: { id3: 1, id4: 1, id5: 1 },
   123213: { id4:1, id5: 1, id77: 1 }
}

当然,每次添加对象时,您还需要更改计数对象。您可能还考虑创建一个作业,以确保计数和地图对象同步。如果没有,请更正。

并且根据您的内存要求,您可能希望在首次请求时创建计数对象。一段时间“不活动”后,您可以清除一些结果。

总而言之,您可以将此问题视为预缓存问题

答案 1 :(得分:0)

只需创建第二张地图作为反向字典:

let map = {
    2333: ['id1', 'id2', 'id3', 'id4'],
    1234: ['id3', 'id4', 'id5'],
    123213: ['id4', 'id5', 'id77']
}

let idcounts = {
    'id1': 1,
    'id2': 1,
    'id3': 2,
    'id4': 3,
    'id5': 2,
    'id77': 1
}

在添加新的idcounts[id]时增加id,在删除时减小。

如果您有很多重叠的ID,请考虑创建一个单独的映射,将ID字符串映射到整数键,然后使用字典中的整数。


已经说过,Node.JS的单线程体系结构确实不适合CPU或内存密集型工作。您可能要考虑将查找工作转移到Redis等外部服务,或者使用Go或C ++等语言,并在地图周围使用互斥锁,以允许并行查找访问。