场合
我正在编写一个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参考
使用上面提到的技术重写了我的函数,而我担心这些技术仍然遍历整个数组以找到它的要求,至少我的代码看起来更干净:)
在阅读答案后使用的参考资料:
答案 0 :(得分:3)
我建议大多数支持的数组函数(如果不支持则很容易添加):
[].splice(index, howManyToDelete); // you can alternatively add extra parameters to slot into the place of deletion
[].indexOf(elementToSearchFor);
[].filter(function(){});
其他有用的功能包括forEach
和map
。
我同意将所有工作合并为一个巨大的循环是丑陋的(而且并非总是可行),并且你做得很少,所以可读性绝对是赢家。虽然这些数组函数不需要太多循环。
答案 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;
});
};
给定数组a
,a.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)
如果出于某种原因,您对splice
或filter
方法不满意,那么John Resig有一个很好的(过时的,但仍在工作)方法:http://ejohn.org/blog/javascript-array-remove/