Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 双for循环性能问题_Javascript_Arrays_Performance_Object_For Loop - Fatal编程技术网

Javascript 双for循环性能问题

Javascript 双for循环性能问题,javascript,arrays,performance,object,for-loop,Javascript,Arrays,Performance,Object,For Loop,为模糊的标题道歉,我真的不知道该如何描述这个问题 我最近遇到一个例子,我必须循环一组对象来比较多个值,我选择在for循环中使用for循环来比较每个对象和其他对象 虽然这在小型阵列上运行良好,但一旦我的阵列变大一点(比如10000个对象),性能就会成为一个大问题 此数组包含以下类型的对象: [{ char: '_', from: 0, to: 2, chrLength: 2 }, { char: '_', from: 0, to: 7, chrLength: 7 }, { char: 'a', f

为模糊的标题道歉,我真的不知道该如何描述这个问题

我最近遇到一个例子,我必须循环一组对象来比较多个值,我选择在for循环中使用for循环来比较每个对象和其他对象

虽然这在小型阵列上运行良好,但一旦我的阵列变大一点(比如10000个对象),性能就会成为一个大问题

此数组包含以下类型的对象:

[{ char: '_', from: 0, to: 2, chrLength: 2 },
{ char: '_', from: 0, to: 7, chrLength: 7 },
{ char: 'a', from: 1, to: 3, chrLength: 2 },
{ char: 'a', from: 1, to: 6, chrLength: 5 },
{ char: '_', from: 2, to: 7, chrLength: 5 },
{ char: 'a', from: 3, to: 6, chrLength: 3 }]
我的想法是,我只能选择
from
to
不与任何其他对象重叠的对象。(
from
to
是另一个数组中的索引)

因此,对于示例阵列,可能的结果是:

[{ char: '_', from: 0, to: 2, chrLength: 2 },
 { char: 'a', from: 1, to: 3, chrLength: 2 },
 { char: 'a', from: 1, to: 6, chrLength: 5 },
 { char: 'a', from: 3, to: 6, chrLength: 3 }]
我的处理方式如下:

var canUse = true,
    posibilities = [];
for(i = 0; i < l; i++) {
    canUse = true;
    for(var j = 0; j < l; j++) {
        if((results[i].from < results[j].from && results[i].to > results[j].to)) {
            canUse = false;
            break;
        }
    }

    if(canUse) posibilities.push(results[i]);
}
var canUse=true,
可能性=[];
对于(i=0;iresults[j].to)){
canUse=false;
打破
}
}
如果(可以使用)可能性推送(结果[i]);
}

看到较大数组的性能非常糟糕,我想知道是否有更好的解决方案来实现这一点?

首先在
chrLength
属性上对对象进行排序。查找阻止包含对象的对象时,只需检查至少短两个字符的对象

results.sort(function(x, y){ return x.chrLength - y.chrLength; });

var posibilities = [];
for (var i = 0; i < l; i++) {
  var canUse = true, len = results[i].chrLength - 2;
  for (var j = 0; results[j].chrLength <= len; j++) {
    if((results[i].from < results[j].from && results[i].to > results[j].to)) {
      canUse = false;
      break;
    }
  }
  if(canUse) posibilities.push(results[i]);
}
这将
属性的检查从
属性分为两个阶段,因此完整检查的数量(其中
映射[j][k]。计算到
)实际上小于对象的总数


免责声明:当然,您需要验证代码是否正确。我已经检查了结果是否有相同数量的项目,但我没有比较每个项目。

对于初学者来说,一旦
canUse
false
您就不需要继续进行内部循环

您可以添加一个
中断或将第二个for循环更改为:

for(var j=0;canUse&(j

您可能会看到一个有用的加速。

以下是想法():

  • 您需要某种自平衡树来支持O(logn)的插入和删除操作。为了简单起见,我使用了红黑树
  • 您需要使用间隔的中点作为键,即
    (从+到)/2
  • 假设您已经将
    k
    项“插入”到树中,并且即将插入
    k+1
    。你的步骤是:
  • 如果
    k+1
    覆盖根-忽略它
  • 如果
    k+1
    被根覆盖,请从树中删除根并再次尝试
  • 否则,通过比较
    k+1
    的mid和根的mid,继续向左或向右子树
  • 插入所有内容后,遍历收集每个节点的结果树
  • 利润。。。我已经使用了你的数组的4倍,通过将它与自身合并。我的机器在Chrome下的结果是116ms(冷启动)和64ms(预热后)
  • 代码

    函数过程(){
    console.log('长度的处理结果:'+l);
    控制台。时间(“处理”);
    var comparator=函数(a,b){//用于构建树的比较器
    返回a.mid-b.mid;
    },
    isAinB=函数(a,b){//util函数,用于检查a是否在b内部
    返回b.froma.to;
    },
    rbtree=newrbtree(comparator),//构建一个空树
    i=结果。长度-1,项目,可能性=[];
    函数检查(根,x){//递归检查器
    var数据;
    如果(!root){//树是空的,或者我们到达了一片叶子
    rbtree.插入(x);
    返回;
    }
    data=root.data;
    if(isAinB(data,x)){//4
    返回;
    }
    if(isAinB(x,data)){//5
    删除(数据);
    检查(rbtree.\u根,x);
    返回;
    }    
    检查(根[比较器(数据,x)>0?'left':'right'],x);//6
    }
    对于(;i>=0;i--){
    项目=结果[i];
    item.mid=(item.from+item.to)/2;//2
    选中(rbtree._root,item);//3
    }
    rbtree.each(功能(项目){//7
    可能性。推送(项目);
    });
    console.timeEnd(“处理”);
    console.log(posibility.length);
    }
    

    顺便说一句,我用过这个。不确定它是否是最好的:)

    不应该
    {char:''u',from:2,to:7,chrLength:5}
    在结果中?@LIUFA:不,因为
    {char:'a',from:3,to:6,chrLength:3}
    适合它。@Jashwant不太确定你的意思,你能提供一个小例子吗?@woutr\u,对不起,误解了你的问题。删除了我的评论。正确的数据结构会有所帮助。很好的地方,完全忽略了这一点。谢谢,这似乎确实减少了检查的数量,但对于一些更大的阵列,仍然需要相当多的时间。只是想知道在执行for之前是否有任何方法可以消除项目loop@woutr_be:对于较大的集合,检查的数量如何变化?考虑到你不能得到比O(n)更好的,即至少每项检查一次。你能举一个更大的例子吗?在一个小集合中很难找到任何有用的模式,可以用于省略。当然,例如,这里有一个包含1000个项目的模式,还有一个更极端的模式:(虽然我的最终数组大小是原来的两倍)@woutru\u-be:Nice,这使得测试一些想法更容易。我做了一些改进,并在上面发布了代码。可能会进行更多的优化,但很难对代码中实际发生的情况进行分析,因为它几乎不会使用那么多数据运行。浏览器实际上崩溃了一次。:)伙计们,我觉得你们走错了路。您需要某种数据结构来回答“如果给定间隔
    var map = [];
    for (var i = 0; i < l; i++) {
      var ch = results[i].chrLength;
      while (map.length <= ch) map.push([]);
      map[ch].push(results[i]);
    }
    for (var i = 1; i < map.length; i++) {
      map[i].sort(function(x, y){ return x.from - y.from; });
    }
    
    var posibilities = [];
    for (var i = 0; i < l; i++) {
      var canUse = true, len = results[i].chrLength - 2, from = results[i].from, to = results[i].to;
      for (var j = 1; canUse && j <= len; j++) {
        if (map[j][map[j].length - 1].from > from) {
          var k;
          for (k = 0; map[j][k].from <= from; k++);
          for (;k < map[j].length && map[j][k].from < to; k++) {
            if (map[j][k].to < to) {
              canUse = false;
              break;
            }
          }
        }
      }
      if(canUse) posibilities.push(results[i]);
    }
    
     function process() {
        console.log('Processing results of length: ' + l);
    
        console.time('Processing');
    
        var comparator = function(a, b) { //Comparator to build a tree
               return a.mid - b.mid;
            },
            isAinB = function(a, b) { //util function to check if a is inside b
                return b.from < a.from && b.to > a.to;    
            },
            rbtree = new RBTree(comparator), //Build an empty tree
            i = results.length - 1, item, posibilities = [];
    
        function check(root, x) { //Recursive checker
            var data;        
    
            if(!root) { //Either tree is empty or we've reached a leaf
                rbtree.insert(x);
                return;
            }
    
            data = root.data;
    
            if(isAinB(data, x)) { //4
                return;    
            }
            if(isAinB(x, data)) { //5
                rbtree.remove(data);
                check(rbtree._root, x);
                return;
            }    
    
            check(root[comparator(data, x) > 0 ? 'left' : 'right'], x); //6
        }
    
        for(; i >= 0; i--) { 
            item = results[i];
            item.mid = (item.from + item.to)/2; //2
            check(rbtree._root, item); //3
        }
    
        rbtree.each(function(item) { //7
            posibilities.push(item);
        });
        console.timeEnd('Processing');
    
        console.log(posibilities.length);
    }