I have seen many questions concerning randomly selecting array items without repeating. However, most of them are answered by using the splice method. But this removes items
If you want to go through an array in random order without modifying the original array:
ary.slice()
(this will copy the array, but not its values if they are objects).var items = ["a", "b", "c", "d", "e", "f", "g"];
var copy = getShuffledCopy(items);
copy.forEach(function (el) {
console.log(el);
});
function getShuffledCopy(ary){
var copy = ary.slice();
shuffle(copy);
return copy;
}
function swap(ary, pos1, pos2) {
var tmp = ary[pos1];
ary[pos1] = ary[pos2];
ary[pos2] = tmp;
}
function shuffle(ary){
// Fisher-Yates shuffle
for(var i = ary.length - 1; i >= 1; i -= 1) {
swap(ary, Math.floor(Math.random() * i), i);
}
}
Try
var items = []
, res = null
, dfd = new $.Deferred()
, processItems = function (item) {
var index = $.inArray(item, items);
console.log("random number: " + index);
$("<div />", {
"class": "TitleText",
"html": $(item).children().find("author_name")[0].innerHTML,
"data-index": index
})
.add("<br />")
.add(
$("<div />", {
"class": "Image",
"data-index": index,
"html": $("<img />", {
"class": "Image",
"data-index": index,
"src": $(item).children()
.filter("media\\:content")
.children("media\\:thumbnail")
.attr("url") + "?" + $.now(),
"width": "145"
})
})
)
.appendTo(".items")
}
, loadXML = function() {
return $.post("/echo/xml/", {xml:xml}, "xml")
.then(function(xml) {
$(xml.documentElement)
.find("item")
.each(function(i, el) {
items.push(el)
});
return items
})
};
loadXML()
.then(function(data) {
$.each(data, function(i, item) {
setTimeout(function() {
// select different randomly selected items,
// without repetition
processItems(item); ++res;
if (res === data.length) {
dfd.resolve(res + " items processed");
}
}, 1 + Math.floor(Math.random() * 25));
});
return $.when(dfd, data)
}, function(jqxhr, textStatus, errorThrown) {
console.log(textStatus, errorThrown)
})
.then(function(msg, data) {
console.log(msg, data)
});
jsfiddle http://jsfiddle.net/guest271314/o5tfs48r/
I don't get very well what you're trying to achieve, but here's one way I'd get random items once
var letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"];
var getRandom = (function (array) {
var notGivenItems = array.map(function (el) {return el;}),
var getIndex = function () {
return Math.floor(Math.random() * notGivenItems.length);
};
return function () {
if (notGivenItems.length === 0) {
return;
}
return notGivenItems.splice(getIndex(), 1)[0];
};
})(letters); // items, in your case
getRandom(); // some letter
getRandom(); // some other letter
...
getRandom(); // different letters until all are given
// if the method is called more times than the array length it'll return undefined
EDIT: Improved performance due to @JLRishe comment