Random Ordered Divs - javascript

I have a quiz that has 100+ questions. When the questions load, only 50 of the questions show. The rest are hidden. I am using the following code:
CSS
.question{
display:none;
}
HTML
<div class="question">
<!-- Code for Each Question -->
</div>
<!-- Repeat 'question div' for every question. -->
JS
var divs = $("div.question").get().sort(function(){
return Math.round(Math.random())-0.5;
}).slice(0,50)
$(divs).show();
The above code works great, however, instead of just showing 50 questions I would like to show 50 questions in a random order. How would I modify my code to not only show only 50 questions but show them in a random order?
I should note that the above JS was used from another question. I don't fully understand Math.random() and unsure how to randomly display the 50 divs that it does show.
Note: Solution must be pure client side code.

To re-order the divs on the page, you will need to re-append them in the shuffled order. What you're currently doing is getting the elements, selecting 50 of them and showing those (in random sequence, but not changing their position in the dom).
Instead of $(divs).show(); use
$(divs).appendTo(questionContainer).show();
Also notice that you shouldn't use sort() to shuffle an array.

first, create an array containing 0-99 (if you have 100 questions)
var arr = new Array();
for(var i=0; i < 100; i++){
arr[i] = i;
}
then shuffle the array
var shuffle = function(o){ //v1.0
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
var shuffled = shuffle(arr);
then loop through the shuffled array showing the first 50.
for(var i = 0; i < 50; i++){
var thisOne = $($("div.question")[shuffled[i]]);
thisOne.parent().append(thisOne);
thisOne.show();
}
I cannot guarantee this will copy paste in and work, but it should get you started.

It sounds like you actually want to move the elements around on the page.
Assuming the questions are within a container div, something like this might do the trick:
var $divs = $("div.question").sort(function(){
return Math.round(Math.random())-0.5;
}).slice(0,4)
// remove them
$divs.detach();
// reposition them
$('#questionContainer').append($divs);
// show
$divs.show();

Related

Loop reload same trial instead of next one Qualtrics

I have a problem with Qualtrics Loop and Merge + Javascript. Basically, Qualtrics reload the previous trial of my loop instead of a new one.
First, here is what I try to do: I have two sets of pictures, at each loop, one picture of each set is randomly picked and displayed (randomly to the left or right side). At the end of the loop, each pictures of the set will be displayed (33 in each set, so 33 trials of the loop), without picking twice the same picture. At each trial, I also display randomly the name of the condition "in relationship" or "friends"
The problem in details:
I have coded something that seems to work quite well, except at some point: It happens that when loading the next trial of the loop, it doesn't display new pictures but instead the one that were presented in the previous trial (and also the same name of condition). This can go for a while presenting me always the same pictures, or this can just be one time.
In any case, this trial which is represented count as a trial, as my loop always ends after 33 trials, whatever if some of these are actually not new pictures presented.
This problem doesn't appear always at the same trial, and can appear several times in a loop.
It also happened that only one picture displayed is new, and the other is the one presented in the previous trial. (I really don't get how this can happen).
I coded the randomisation of picture in an empty question, just before the question where it displays the pictures. This empty question is supposed to not require to press the "next" button. When the trial are correct, this is working well, but when the next trial is going to be one "reloaded" trial, it requires to press the "next" button.
I tried the survey with Firefox and Edge, and the problem is the same.
My javascript code:
In the first question of the survey:
Qualtrics.SurveyEngine.addOnload(function () {
function shuffle(o) { //v1.0
for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
var FacesM_list = "IM_7U04c3TQlA7dT3D,IM_eE5iBcKfoOblbJH,IM_a3mklzA9E1OuRWl,IM_bQnoSJOGwa0vn9P,IM_5inNCVgPdHHTVSR,IM_bHlurQJWSXDRDFj,IM_3rCr2DIzW2cvqLP,IM_509x1wz7pM6PP0N,IM_3UGdsp02IcCqaSV,IM_eLrY7bwDPiT7apn,IM_3LdlHnBb6tnkBEh,IM_3pY6z6JDgaDvwq1,IM_9HtZxBS79DiOfR3,IM_03c9pDSpcwcqIyF,IM_6WGKJOzUWK4TJat,IM_2rxQPEGO7SEvsY5,IM_9YN3UCUtWEWTfGR,IM_8jZTSUAGJfuVECV,IM_9nQkFhRY2cLIVgN,IM_2abcJA7B79jt30h,IM_cD31N8XPTGliUN7,IM_0eL8iQd4PVdyuQl,IM_cuOoV9gSAe6CWd7,IM_9Nv3X7lWYEsTzsF,IM_5ccXAuuomEEyamp,IM_9mnvThFiNA5U84t,IM_e3UGNNuMdrKH8cl,IM_3aggsd5P9MMlUDr,IM_4ORY6GEMW8CmNPT,IM_50WOBkz8ADTFGHH,IM_3rqtlVBfijYCccZ,IM_3CzDsr0tYv7PH5H,IM_4SmeprjDgOeCl5b"
var FacesF_list = "IM_6fkHDs5f6ItAuk5,IM_0ri9MLjDhHxyonP,IM_bKlHtoAaxnBFlnT,IM_1WUqtBPpdhERpjf,IM_ac0yWos8tAqSMNT,IM_3xCePACn1Lq97tH,IM_6o1ZPLGUM682Au1,IM_babATdN3VtBLIsl,IM_8HSUICLvFvDXaN7,IM_0ebTztq3ML5Zh0V,IM_3lB8j5dhMs8i8ip,IM_0iC0pwDlpOkcTGt,IM_cIRojwU6sx3W7Od,IM_9ZHNbignrAfcThX,IM_8iFXvVcCqk5hemN,IM_6rrwImdl4Nss0u1,IM_6mPEaoIdazwqAWp,IM_b8lrxhsPGcc1HaR,IM_23uYWeF2gYVMsap,IM_6ycfrm5xOlewjFb,IM_7UKValFGc9Kmpp3,IM_8Bbkzsmc7CyMvqt,IM_d5S95FnSgo8j06F,IM_brXT4VUU8QJiRwN,IM_9MEkpgEmOwXhril,IM_6KG9qokOlD16GDH,IM_ellgVnYbtb8ZSbb,IM_eg6qSYMQ56z5JpX,IM_5vfbDNPdZeP1XCZ,IM_cDbOprwCUUSnUZT,IM_cumIGHXOFByV4Pz,IM_0jh2Va4JTfGsQDz,IM_0CGlFRy4dW8lDcF"
var FacesM_order = [];
for (var i = 1; i <= 33; i++) {
FacesM_order.push(i);
}
FacesM_order = shuffle(FacesM_order);
var FacesF_order = [];
for (var i = 1; i <= 33; i++) {
FacesF_order.push(i);
}
FacesF_order = shuffle(FacesF_order);
var nTrial = 0;
Qualtrics.SurveyEngine.setEmbeddedData("FacesM_order", FacesM_order.toString());
Qualtrics.SurveyEngine.setEmbeddedData("FacesF_order", FacesF_order.toString());
Qualtrics.SurveyEngine.setEmbeddedData("FacesF_list", FacesF_list.toString());
Qualtrics.SurveyEngine.setEmbeddedData("FacesM_list", FacesM_list.toString());
Qualtrics.SurveyEngine.setEmbeddedData("nTrial", nTrial.toString());
});
And in the first question of the Block with Loop and Merge:
Qualtrics.SurveyEngine.addOnload(function () {
var nTrial = Number("${e://Field/nTrial}") + 1;
var FacesF_list = "${e://Field/FacesF_list}".split(',');
var FacesM_list = "${e://Field/FacesM_list}".split(',');
var FacesF_order = "${e://Field/FacesF_order}".split(',');
var FacesM_order = "${e://Field/FacesM_order}".split(',');
var FacesF = FacesF_list[FacesF_order[nTrial]];
var FacesM = FacesM_list[FacesM_order[nTrial]];
var rand = Math.random()
if (rand < 0.5) {
var left = FacesF
var right = FacesM
} else {
var left = FacesM
var right = FacesF
}
Qualtrics.SurveyEngine.setEmbeddedData("nTrial", nTrial.toString());
Qualtrics.SurveyEngine.setEmbeddedData("left", left.toString());
Qualtrics.SurveyEngine.setEmbeddedData("right", right.toString());
this.clickNextButton.delay(.00000000000001);
});
Thanks a lot for your help!

Unique random values from array of unique values javascript

I have twelve squares and six of those are selected randomly and a style then applied. This is achieved by generating random values from an array of unique values. The problem is the random values being generated aren't unique e.g 5 could be chosen more than once. I've looked at so many posts on here and there seems to be a number of different ways of achieving this - shuffling etc. Which would be the most effective?
for (var i = 0; i < 6 ; i++)
(function (i) {
setTimeout(function () {
var rand = arr[Math.floor(Math.random() * arr.length)];
var square = document.getElementById('square' + rand);
square.style.background = black;
if (i == 6) Reset();
}, 1500 * i);
})(i);
};
Just for the sake of simplicity I will assume your elements have a class.
Example on jsFiddle
So, I would grab all elements:
var elements = document.getElementsByClassName("square");
Then I would create an array with the IDs
var ids = [];
for (var i = 0; i < elements.length; ++i)
{
ids.push(elements[i].getAttribute("id"));
}
And then generate random numbers on the length of the array
var random = roundingFunction(Math.random() * ids.length);
Then retrieve the element at the index and remove from the array
var elementID = ids.splice(random, 1);
And repeat.
There are bascially three different approaches:
Pick an item by random and repeat if it was used before.
Put all items in an array, pick by random and remove from the array.
Put all items in an array and shuffle.
Which one would be the most efficient can't be answered in the scope of your question. The difference between them is so small that it negligible considering how much the performance differs between browsers.
If you really need the most efficient, you have to try them all and test the performance in a wide variety of browser.
Otherwise just pick the one that seems easiest to implement. The are all good enough for any normal application.

Optimizing JavaScript autocorrect implementation

I modified the jQuery Autocomplete implementation to generate autocorrect suggestions too. I used Levenshtein distance as the metric to decide closest matches.
My code runs at each keypress after the jQuery autocomplete does not have any more suggestions. Here's the code that I wrote:
// Returns edit distance between two strings
edit_distance : function(s1, s2) {
// Auxiliary 2D array
var arr = new Array(s1.length+1);
for(var i=0 ; i<s1.length+1 ; i++)
arr[i] = new Array(s2.length+1);
// Algorithm
for(var i=0 ; i<=s1.length ; i++)
for(var j=0 ; j<=s2.length ; j++)
arr[i][j] = 0;
for(var i=0 ; i<=s1.length ; i++)
arr[i][0] = i;
for(var i=0 ; i<=s2.length ; i++)
arr[0][i] = i;
for(var i=1 ; i<=s1.length ; i++)
for(var j=1 ; j<=s2.length ; j++)
arr[i][j] = Math.min(arr[i-1][j-1] + (s1.charAt(i-1)==s2.charAt(j-1) ? 0 : 1), arr[i-1][j]+1, arr[i][j-1]+1);
// Final answer
return arr[s1.length][s2.length].toString(10);
},
// This is called at each keypress
auto_correct : function() {
// Make object array for sorting both names and IDs in one go
var objArray = new Array();
for(var i=0 ; i<idArray.length ; i++) {
objArray[i] = new Object();
objArray[i].id = idArray[i];
objArray[i].name = nameArray[i];
}
// Sort object array by edit distance
var out = this;
companyObjArray.sort (
function(a,b) {
var input = jQuery("#inputbox").val().toLowerCase();
var d1 = a.name.toLowerCase();
var d2 = b.name.toLowerCase();
return out.editDistance(input,d1) - out.editDistance(input,d2);
}
);
// Copy some closest matches in arrays that are shown by jQuery
this.suggestions = new Array();
this.data = new Array();
for(var i=0 ; i<5 ; i++) {
this.suggestions.push(companyObjArray[i].name);
this.data.push(companyObjArray[i].id);
}
}
All names have IDs associated with them, so before sorting I'm just creating an object array out of them, and sorting the array.
Since the list to search from is in thousands, its slow. I found a data structure called a BK-tree, which can speed it up, but I'm can't implement it right now. I'm looking for optimization suggestions to speed this up. Any suggestions are welcome. Thanks in advance.
EDIT. I decided to use Sift3 as my string distance metric instead of Levenshein distance, it gives more meaningful results and is faster.
There are quite a few things you can optimize here, but most of it boils down to this: Only do each of your 'heavier' calculations once. You are doing a lot of work on each keypress, in every sort comparison, etc., and caching those values will help a lot.
However, for a significant added performance boost, there is another, quite nifty optimization trick you can use. It is used by every major search engine, including on-site search engines on sites such as Amazon.com.
It takes advantage of the fact that you really don't need to sort the whole list, since all you're displaying are the top 10 or 12 items. Whether the rest of the thousands of list items are in the correct order doesn't matter in the least. So all you really have to keep track of while running through the list, are the top 10 or 12 items you've seen so far, which, as it turns out, is a lot faster than full sorting.
Here's the idea in pseudocode:
The user types a character, creating a new search term
We define an empty shortlist array of length 12 (or however many suggestions we want)
Loop through the full list of words (we will call it the dictionary):
Calculate the (Levenshtein) edit distance between the dictionary word and the search term
If the distance is lower (better) than the current threshold, we:
Add the word to the top of the shortlist
Let the bottom word in the shortlist 'overflow' out of the list
Set our threshold distance to match the word now at the bottom of the shortlist
When the loop has finished, we have a shortlist containing some of the best words, but they are unsorted, so we sort just those 12 words, which will be really fast.
One small caveat: Depending on the dataset and the number of elements in your shortlist, the shortlist may differ slightly from the actual top elements, but this can be alleviated by increasing the shortlist size, e.g. to 50, and just removing the bottom 38 once the final sort is done.
As for the actual code:
// Cache important elements and values
var $searchField = $('#searchField'),
$results = $('#results'),
numberOfSuggestions = 12,
shortlistWindowSize = 50,
shortlist,
thresholdDistance;
// Do as little as possible in the keyboard event handler
$searchField.on('keyup', function(){
shortlist = [];
thresholdDistance = 100;
// Run through the full dictionary just once,
// storing just the best N we've seen so far
for (var i=0; i<dictionarySize; i++) {
var dist = edit_distance(this.value, dictionary[i]);
if (dist < thresholdDistance) {
shortlist.unshift({
word: dictionary[i],
distance: dist
});
if (shortlist.length > shortlistWindowSize) {
shortlist.pop();
thresholdDistance = shortlist[shortlistWindowSize-1].distance;
}
}
}
// Do a final sorting of just the top words
shortlist.sort(function(a,b){
return a.distance - b.distance;
});
// Finally, format and show the suggestions to the user
$results.html('<p>' + $.map(shortlist, function(el){
return '<span>[dist=' + el.distance + ']</span> ' + el.word;
}).slice(0,numberOfSuggestions).join('</p><p>') + '</p>').show();
});
Try the method out in this 12.000 word demo on jsFiddle

Get array values and put them into different divs with a for loop?

I'm trying hard to learn javascrip+jquery on my own, and also trying to learn it right. Thus trying to enforce the DRY rule.
I find myself stuck with a problem where I have an array,
var animals = [4];
a function,
var legs = function(amount){
this.amount = amount;
this.body = Math.floor(Math.random()*amount)+1;
}
and an evil for loop. I also have 5 div's called printAnimal1, printAnimal2 and so on.. In which I wish to print out each value in the array into.
for(i = 0; i < animals.length; i++){
animals[i] = new legs(6);
$(".printAnimal"+i).append("animals[i]");
}
I feel as if I'm close to the right thing, but I cant seem to figure it out. I also tried something like this:
for(i = 0; i < animals.length; i++){
animals[i] = new legs(6);
$this = $(".printAnimal");
$(this+i).append("animals[i]");
}
But one of the problems seem to be the "+i" and I cant make heads or tails out of it.
I also know that I can simply do:
$(".printAnimal1").append("animals[i]");
$(".printAnimal2").append("animals[i]");
$(".printAnimal3").append("animals[i]");
...
But that would break the DRY rule. Is it all wrong trying to do this with a for loop, or can it be done? Or is there simply a better way to do it! Could anyone clarify?
Your first attempt should be fine, as long as you take "animals[i]" out of quotes in your append() call ($(".printAnimal"+i).append(animals[i]))
Also, I assume you declared var i; outside your for loop? If not, you'll want to declare it in your for loop (for(var i=0....)
EDIT: problems with your fiddle
you never call startGame()
you didn't include jQuery
you can't (as far as I know) append anything that isn't html-- in your case, you're trying to append a js object. What do you want the end result to look like?
http://jsfiddle.net/SjHgh/1/ is a working fiddle showing that append() works as you think it should.
edit: forgot to update the fiddle. Correct link now.
EDIT: reread your response to the other answer about what you want. http://jsfiddle.net/SjHgh/3/ is a working fiddle with what you want. More notes:
You didn't declare new when you called DICE
you have to reference the field you want, (hence dices[i].roll), not just the object
Just a few comments:
This is declaring an array with only one item and that item is the number 4
var animals = [4];
In case you still need that array, you should be doing something like:
var animals = []; // A shiny new and empty array
and then add items to it inside a for loop like this:
animals.push(new legs(6)); //This will add a new legs object to the end of the array
Also, what is the content that you are expecting to appear after adding it to the div?
If you want the number of legs, you should append that to the element (and not the legs object directly).
for(i = 0; i < animals.length; i++){
animals.push(new legs(6));
$(".printAnimal"+i).append(animals[i].body);
}
Adding another answer as per your comment
var i, dicesThrown = [];
function throwDice(){
return Math.ceil(Math.random() * 6);
}
//Throw 5 dices
for (i=0 ; i<5 ; i++){
dicesThrown.push( throwDice() );
}
//Show the results
for (i=0 ; i<5 ; i++){
$("body").append("<div>Dice " + (i+1) + ": " + dicesThrown[i] +"</div>");
}

using javascript shuffled integers to populate sequential html areas

I'm trying to change the contents of sequential divs with randomly-ordered contents. It's not working so well.
I have about 25 <div> tags that, because of other javascripts regulating touch behaviour, are unable to be put in a randomised order using the usual methods. So instead, I'm trying to have the contents of those <div>s randomised by setting different innerHTML values when the document is loaded.
I have a script that provides random integers as I need, but then I'm having trouble getting it to populate the ordered divs.
Here's what I'm using that isn't working:
ArrayList<Integer> list = new ArrayList<Integer>(25);
for(int i = 0; i < 25; i++)
{
list.add(i);
}
Collections.shuffle(list);
Object[] randomNumbers = (Object[])list.toArray();
function testit() {
for(int i = 0; i < 25; i++)
{
var a = document.getElementById('if'+i);
a.innerHTML = randomNumbers[i];
}
}
What I'd like to see is that this takes all my <div>s which have id's such as "if1" "if2" and so one and then set the content of that <div> with the randomised numbers.
I know document.getElementById('if'+i) is surely the wrong way to get ID "if1" then "if2", but I'm not really sure how else it can be done.
Basically I just need a way to populate 25 absolutely-positions <div>s with 25 chunks of HTML content but in a random order. I'd think that could be done by pairing sequential numbers to randomly ordered numbers and tying those into <div> id's. Normally I'd just do this with PHP and be done already but I need it to work as an offline mobile webapp so I'm trying to do it with JS and CSS. I'm definitely open to other approaches.
edit:
If the code above is Java and not Javascript, that's the problem. Then I guess I'm looking for alternative ways, in Javascript, to produce random, non-repeating integers and link those to sequential integers, all between 1 and 25
Here is a sample implementation using javascript:
function shuffle(arr){
//simple shuffle algorithm - you can also use other
//we will get simple base index as basis for swapping elements
//we will swap the array elements arr.length times
var index = Math.floor(Math.random() * arr.length);
for(var i=1;i<arr.length; i++) {
var t = arr[i];
arr[i] = arr[index];
arr[index] = t;
}
return arr;
}
//create an array
var numbers =[];
for(var i=0;i<10;i++)
numbers.push(i);
//call the shuffle function
//call this many times to reshuffle elements
numbers = shuffle(numbers);
//document.write(numbers.join(','));
//test
for(var i=0;i<numbers.length;i++)
{
var a = document.getElementById('if'+i);
a.innerHTML = numbers[i];
}

Categories