在javascript中循环for()的过多替代品

时间:2011-06-25 21:03:13

标签: javascript jquery arrays sorting loops

场合

我正在编写一个javascript小部件,它在html元素中显示随机引用。引号存储在javascript数组中,以及它们显示在html元素中的次数。要显示的报价不能与之前显示的报价相同。此外,选择引用的机会是基于它在html元素中的先前出现。 (与选择显示的其他报价相比,较少出现的机会应该导致更高的机会。

当前解决方案

我目前通过使用大量循环遍历各种数组使其工作(我严重缺乏javascript知识)。虽然目前有效(!!)但我发现这个解决方案对于我想要实现的目标来说相当昂贵。

我在寻找什么

  • 从数组中删除数组元素的替代方法,当前循环遍历整个数组以查找我想删除的元素并将所有其他元素复制到新数组中
  • 根据数据的出现计算和从数组中选择元素的替代方法
  • 您注意到的任何其他内容我应该/可以做的不同,同时仍然在情境
  • 下执行规定的业务规则

守则

var quoteElement = $("div#Quotes > q"),
    quotes = [[" AAAAAAAAAAAA ", 1],
              [" BBBBBBBBBBBB ", 1],
              [" CCCCCCCCCCCC ", 1],
              [" DDDDDDDDDDDD ", 1]],
    fadeTimer = 600,
    displayNewQuote = function () {

                        var currentQuote = quoteElement.text();
                        var eligibleQuotes = new Array();
                        var exclusionFound = false;
                        for (var i = 0; i < quotes.length; i++) {
                            var iteratedQuote = quotes[i];
                            if (exclusionFound === false) {
                                if (currentQuote == iteratedQuote[0].toString())
                                    exclusionFound = true;
                                else
                                    eligibleQuotes.push(iteratedQuote);
                            } else
                                eligibleQuotes.push(iteratedQuote);
                        }
                        eligibleQuotes.sort( function (current, next) {
                            return current[1] - next[1];
                        } );

                        var calculatePoint = eligibleQuotes[0][1];
                        var occurenceRelation = new Array();
                        var relationSum = 0;
                        for (var i = 0; i < eligibleQuotes.length; i++) {
                            if (i == 0)
                                occurenceRelation[i] = 1 / ((calculatePoint / calculatePoint) + (calculatePoint / eligibleQuotes[i+1][1]));
                            else
                                occurenceRelation[i] = occurenceRelation[0] * (calculatePoint / eligibleQuotes[i][1]);
                            relationSum = relationSum + (occurenceRelation[i] * 100);
                        }

                        var generatedNumber = Math.floor(relationSum * Math.random());
                        var newQuote;
                        for (var i = 0; i < occurenceRelation.length; i++) {
                            if (occurenceRelation[i] <= generatedNumber) {
                                newQuote = eligibleQuotes[i][0].toString();
                                i = occurenceRelation.length;
                            }
                        }

                        for (var i = 0; i < quotes.length; i++) {
                            var iteratedQuote = quotes[i][0].toString();
                            if (iteratedQuote == newQuote) {
                                quotes[i][1]++;
                                i = quotes.length;
                            }
                        }

                        quoteElement.stop(true, true)
                                    .fadeOut(fadeTimer);
                        setTimeout( function () {
                            quoteElement.html(newQuote)
                                        .fadeIn(fadeTimer);
                        }, fadeTimer);

                    } 

if (quotes.length > 1) 
    setInterval(displayNewQuote, 10000);

考虑的替代方案

  • 始终选择具有最低出现次数的数组元素。

    决定反对,因为这会/可能会在动画中显示一个太明显的模式

  • 组合多个for循环以减少工作量

    决定反对这一点,因为这会使代码变得深奥,我可能不会再理解下周的代码了

jsFiddle参考

http://jsfiddle.net/P5rk3/

更新

使用上面提到的技术重写了我的函数,而我担心这些技术仍然遍历整个数组以找到它的要求,至少我的代码看起来更干净:)

在阅读答案后使用的参考资料:

5 个答案:

答案 0 :(得分:3)

我建议大多数支持的数组函数(如果不支持则很容易添加):

[].splice(index, howManyToDelete); // you can alternatively add extra parameters to slot into the place of deletion
[].indexOf(elementToSearchFor);
[].filter(function(){});

其他有用的功能包括forEachmap

我同意将所有工作合并为一个巨大的循环是丑陋的(而且并非总是可行),并且你做得很少,所以可读性绝对是赢家。虽然这些数组函数不需要太多循环。

答案 1 :(得分:2)

你想要的答案:

创建一个整数数组,用于存储每个引号的使用次数。此外,全局变量Tot具有已使用的引号总数(即,该整数数组的总和)。还可以Mean查找Tot / number of quotes

选择0到Tot - 1之间的随机数。

对于每个报价,添加Mean * 2 - the number of uses(* 1)。当您得到该值超过生成的随机数时,请选择该引用。

如果报价是当前显示的报价,请选择下一个或上一个报价,或者只是重复该过程。

真正的答案:

如果报价重复,请使用随机引用,最大重复次数。当用户重新加载/离开页面时,数据使用将会丢失。而且,无论你多么聪明地选择它们,大多数用户都不在乎。

(* 1)检查限制,即第一个或最后一个配额是否符合此公式。

答案 2 :(得分:1)

  

从数组中删除数组元素的替代方法

使用ES5的Array.filter()方法:

Array.prototype.without = function(v) {
    return this.filter(function(x) {
        return v !== x;
    });
};

给定数组aa.without(v)将返回a的副本,其中不包含元素v

  

与选择用于显示的其他报价相比,较少发生的事件应该导致更高的机会

你不应该有机会 - 正如我的数学家另一半所说,“机会没有记忆”。

你的建议类似于这样的想法,即彩票中尚未出现的数字必须“过期”,因此更有可能出现。事实并非如此。

答案 3 :(得分:0)

您可以编写明确定义您要对循环执行的操作的函数。

您的第一个循环是过滤器。 你的第二个循环是地图+一些副作用。 我不知道其他循环,它们很奇怪:P

过滤器类似于:

function filter(array, condition) {
    var i = 0, new_array = [];
    for (; i < array.length; i += 1) {
        if (condition(array[i], i)) {
            new_array.push(array[i]);
        }
    }
    return new_array;
}

var numbers = [1,2,3,4,5,6,7,8,9];
var even_numbers = filter(numbers, function (number, index) {
    return number % 2 === 0;
});
alert(even_numbers); // [2,4,6,8]

无法避免循环,但您可以通过创建一个解释您正在做的事情的函数,为代码添加更多语义

答案 4 :(得分:0)

如果出于某种原因,您对splicefilter方法不满意,那么John Resig有一个很好的(过时的,但仍在工作)方法:http://ejohn.org/blog/javascript-array-remove/