检查“链条”长度的最佳方法

时间:2013-01-31 06:12:35

标签: jquery optimization

我正在编写一个小型网络应用程序,其中一个用户将有一行n个元素,并且他需要根据自己的标准将每个元素切换为true / false。

每次用户切换元素时,我都必须检查切换元素可能属于的真元素“链”的长度。示例:

0 0 0 0 1 0 1 1 1 ? //if user selects '1', the chain length is 4
0 ? 1 1 0 1 1 0 0 0 //if user selects '1', the chain length is 3
0 0 1 1 1 ? 1 1 0 0 //if user selects '1', the chain length is 6

我正在考虑这样做的最好方法。

所有元素都将在JSON对象和DOM对象中表示(例如<div> s)。

一个选项是每次点击都可以简单地遍历整个数组。这没关系,因为元素的最大数量大约为1000.但它似乎不是最有效的方式。

另一个选项是在计算每个额外的true元素时获取被点击的元素并向后退步,直到达到false元素。然后从点击的元素开始做同样的事情。这对我来说似乎更好,但也许这是一个不必要的麻烦。

我需要帮助确定哪种方法最适合此问题。因素(毫不奇怪) -

  1. 性能 - 它不得在客户端造成任何滞后 - 必须立即确定链长。
  2. 可维护性。
  3. 我意识到这个问题可能看起来有点主观,也许就是这样,但我认为这对于一个我不了解的熟悉解决方案来说一定是一个熟悉的问题。

    我将使用jQuery。

3 个答案:

答案 0 :(得分:2)

我会先找到最长的链条。这将需要迭代您的元素一次。

之后,从每个更改元素的位置向外辐射,找到最长链。

$('.box').click(function() {
    $('.selected').removeClass('selected');

    var $this = $(this);
    $this.toggleClass('active');

    var $next = $this.nextUntil(':not(.active)');
    var $prev = $this.prevUntil(':not(.active)');

    if ($this.hasClass('active')) {
        var $chain = $next.add($prev).add($this);
    } else {
        var $chain = $next.length > $prev.length ? $next : $prev;
    }

    $chain.addClass('selected');
});

如果该链比最长的链长,那么您找到了新的最长链。

演示:http://jsfiddle.net/EDVvN/4/

答案 1 :(得分:1)

我提出了一个似乎“足够有效”的解决方案,因为在我的测试过程中浏览器没有任何延迟。我会说1000个元素与浏览器应该能够处理的内容相比并不多,但对于用户来说它是 lot (在我开始感觉之前,我只能测试点击大约100个元素身体疼痛)。

这适用于一个简单的整数数组,并且在点击它们时除了单个输入元素之外不会触及大部分DOM。我假设对整数数组的操作与排序和聚合的速度差不多。

//record an array of selected indices
var items = [];

//Delegation will speed things up (hopefully)
$("body").on('change', 'input', function () {
    var $this = $(this);
    var index = $this.index();

    //`items` should only ever contain clicked elements
    //We only have to worry about the one item with each click for now
    if ($this.prop('checked')) {
        items.push(index);
    }
    else {
        items.splice(items.indexOf(index), 1);
    }
    items.sort(function (a, b) { return a - b; });
    var chains = [1];
    var chain = 0;
    try {
        //iterate over the items array.  This should be fast even for 100 items
        items.reduce(function (prev, next) {
            //items are out of order; record currently found chain
            if (next - 1 !== prev) {
                chain++;
                chains.push(1);
            }
            else {
                chains[chain]++;
            }
            return next;
        });
    }
    catch (err) {
        //handle TypeError thrown by `.reduce` on empty array
        //this also accounts for the "0" case (no elements selected)
        chains = [0];
    }
    //Get the longest found chain
    console.log(Math.max.apply(undefined, chains));
});

http://jsfiddle.net/ExplosionPIlls/svUrs/2/

答案 2 :(得分:0)

你的想法是从点击元素后退然后转发直到达到零听起来效率高而且不是特别复杂。但是,人们可能会认为它过早优化 - 检查1000个元素不会影响浏览器的响应能力(这对您来说很容易测试),所以如果您认为效率较低的算法编码速度更快和/或更容易维护它可以说是最好的解决方案。