Random Array Repeats Index Items - javascript

This code works fine in their example but repeats some of my index items when I try and use it.
var lastloaded = 0;
window.onload = loadPages;
Array.prototype.knuthShuffle = function()
{
var i = this.length, j, temp;
while ( --i )
{
j = Math.floor( Math.random() * (i - 1) );
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
};
var arr = ["aCard.html", "bCard.html", "cCard.html", "dCard.html"];
function loadPages () {
arr.knuthShuffle();
var frame = document.getElementById("frameWrap");
if (lastloaded+1>arr.length){
lastloaded = window.location = "greatJob.html";
}
frame.src = arr[lastloaded];
lastloaded++;
};
document.getElementById('tom').onclick = loadPages;
Can anyone tell me what I am missing from this code to keep it from repeating items in my array?

I'm not sure I completely understand how your page works, but it seems like it is shuffling the array in order to figure out the next page to go to. This means that it is newly shuffled with every page load, and you therefore have no guarantee as to the uniqueness of the pages - in fact, it would be extremely unlikely for you to get all the unique pages (1 in n!, to be precise)
In order to ensure uniqueness, you MUST save the generated order, not just the index you were at.

You have a problem with your declaration of j and temp which might add up on multiple shuffles and give you some strange behavior.
specifically this line:
var i = this.length, j, temp;
and these lines:
j = Math.floor( Math.random() * (i - 1) );
temp = this[i];
The problem here is that you didn't actually declare the j and temp variables, that's an invalid syntax. Then when declaring them within your loop without the var keyword they are treated as global variables. Solvable by modifying the first line into:
var j, temp;
var i = this.length;
Edit: Actually that isn't it, as already pointed out by t.niese every time you click tom you're re-shuffling.
What you want to do is shuffle once and use the newly shuffled array every time. So decouple your shuffling from your page loading by taking arr.knuthShuffle(); out of the loadPages() function.

Related

How do I correctly split an array of strings of is it another issue?

I am trying to access a random element from an array of strings as per other examples here on SO. I am using Raphael.js and regions[j] below returns an array of Raphael objects - hence the .data(id). This seems to be ok, but theCountyNames, as outlined in the comment below returns all of the strings as one long string. I am guessing that this is why randCounty returns a single random letter, but when I try appending a comma in the loop (+",") and using split as per this question, I still get one random single letter. Perhaps I am implementing this incorrectly or maybe it is another issue? Thanks.
function pickRandCounty(){
var theCountyNames = new Array();
for (var j = 0; j < regions.length; j++) {
theCountyNames = regions[j].data('id');
document.write(theCountyNames);//THIS GIVES ME THE COMPLETE LIST OF ITEMS IN THE ARRAY BUT ALL AS ONE STRING
//document.write("<hr>");
}
//var randCounty = theCountyNames[Math.floor(Math.random() * theCountyNames.length)];
//document.write(randCounty);//THIS JUST RETURNS ONE RANDOM LETTER??
}
Using Array.prototype.push to append a new item to an Array.
function pickRandCounty(){
var theCountyNames = [],
j;
for (j = 0; j < regions.length; ++j) {
theCountyNames.push(regions[j].data('id'));
}
j = Math.floor(Math.random() * regions.length);
return theCountyNames[j];
}
However, this is not optimised as you can set the length of the Array in advance and you can even completely skip the loop,
function pickRandCounty(){
var j = Math.floor(Math.random() * regions.length);
return regions[j].data('id');
}
The error seems to be in this part of line.
theCountyNames = regions[j].data('id'); //wrong
theCountyNames.push(regions[j].data('id')); //right
Second mistake
document.write(theCountyNames); //it will keep on appending the string in the DOM
document.write("<br>" + theCountyNames);//right

How to improve my custom JavaScript Array Reverse Function?

I am looking to improve a function I wrote for array reversal. I was interested in writing my own just for practice and I came up with this:
function rArray(array){
var temp = [];
var len = array.length - 1;
for(i = len, index = 0 ; i >= 0; i--, index++){
temp.push(array[i]); // temp[index] = array[i];
}
return temp;
}
I am looking to 1.) improve speed, and two, create a more efficient function by leaving less of a footprint, I want to make a destructive reversing function. Can this be done with a for loop or must I use a while()? Thanks for the input.
You could get rid of index, since you aren't using it.
Or you could pre-allocate temp
var temp = new Array(len);
You can't do both, though, since you would need index to add to the pre-allocated temp. You could run some experiments to see at what length pre-allocation becomes preferable (my guess: several million).

For Loop Manipulate Multidimensional Array Javascript

Okay so I have a 2D array that I am trying to alter using javascript. This is what I have so far:
for (var i = 0; i <= inputData.length; i++ {
inputData[0,0] = inputData[0,0];
inputData[i,0] = inputData[((i - 1) + 1/12), 0];
I want this to take array [i-1] value and then add 1/12 to it
for (j = 13; inputData.length; j += 13) {
delete inputData[j,0];
delete inputData[j,1];
}
Also, I want to delete the entire 2D array at every 13th increment value.
}
This is what I have so far. I am sure there are probably errors within it. Can you guys help me out here? Any help would be greatly appreciated.
Couple of things - you need to be careful when iterating over an array that you're removing from, your indexes will end up offset with respect to your data as soon as you do a delete. Secondly your syntax for deletion is off.
Normally in these situations I favour creating a new array containing the data I want to keep.
var inputData = [[1,1],[2,2],[3,3],[4,4]];
var b = [];
for (i=0; i < inputData.length; i++) {
if ((i + 1) % 13 != 0) {
var year_with_month = inputData[i][0] + i * 1/12;
var e = [year_with_month, inputData[i][1]]
b.push(e);
}
}
inputData = b;
Also, given a choice I'd use a library like underscore to make it easy to do the looping. I never manually write for loops anymore, took me a couple of attempts to get that one right :)

array passed as parameter issue

I've got 2dim array set as global variable populated with numbers on row - 0 and strings on row-1.
But when I passed it as a parameter to a function most of its values modifies into undefined but in one strangely value is kept!?!
function formElements(howMany){
elArr = [];
var w; var surface;
for(var j=0; j<howMany; j++){
w = randomNumber(1,200);
surface = w*randomNumber(1,100);
elArr[0] =[j];
elArr[1] =[j];
elArr[0][j]=surface;
elArr[1][j]='_'+j;
}
aFunction(elArr,...other parameters....); //in this function I receive array with these undefined values I mentioned above!!!
}
function randomNumber(x,y) {
return Math.floor((Math.abs(y - x) + 1) * Math.random()) + Math.min(x, y);
}
Could somebody tell me what's wrong?
10x and BR
The references to j make it look like this is inside a loop. In which case, I don't think this is doing what you want:
elArry[0] = [j];
This sets the value of elArray[0] to an array with a single element, j. If you're doing that inside your loop then you're overwriting the arrays every time with a new one with a single element.
EDIT:
And now that you've posted the full loop that's verified. You probably want something like:
function formElements(howMany){
elArr = [[],[]];
for(var j=0; j<howMany; j++){
elArr[0][j]=surface;
elArr[1][j]='_'+j;
}
aFunction(elArr,...other parameters....);
}

Why is my nested for loop not working as I expected?

I have trouble dealing with my for loops now, I'm trying to compare two datum, basically it will compare 2 items, then it will write the matches and the mismatches on the webpage.
I managed to write the matches on the webpage, it was working good. But there's a bug in my mismatch compare.
It wrote all the data on the webpage X times, here's my JS code:
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
var count = 0;
var count2 = 0;
for(var i = 0; i < i1.length; i++) {
for(var j = 0; j < i2.length; j++) {
if(i1[i] == i2[j]) {
newArray.push(i1[i]);
count++;
} if (i1[i] !== i2[j]) {
newArray2.push(i1[i]);
count2++;
}
}
}
count-=2;
count2-=2
writeHTML(count,count2, newArray, newArray2);
}
The result was horrible for the mismatches:
alt text http://www.picamatic.com/show/2009/03/01/07/44/2523028_672x48.jpg
I was expecting it to show the mistakes, not all the strings.
The issue you're seeing is because of the nested for loop. You are essentially doing a cross-compare: for every item in i1, you are comparing it to every item in i2 (remember that j starts again at 0 every time i advances... the two loops don't run in parallel).
Since I understand from the comments below that you want to be able to compare one array to the other, even if the items in each are in a different order, I've edited my original suggestion. Note that the snippet below does not normalize differences in case between the two arrays... don't know if that's a concern. Also note that it only compares i1 against i2... not both i1 to i2 and i2 to i1, which would make the task a little more challenging.
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++) {
var found = false;
for (var j = 0; j < i2.length; j++) {
if (i1[i] == i2[j]) found = true;
}
if (found) {
newArray.push(i1[i])
} else {
newArray2.push(i1[i])
}
}
}
As an alternative, you could consider using a hash table to index i1/i2, but since the example of strings in your comment include spaces and I don't know if you're using any javascript helper libraries, it's probably best to stick with the nested for loops. The snippet also makes no attempt to weed out duplicates.
Another optimization you might consider is that your newArray and newArray2 arrays contain their own length property, so you don't need to pass the count to your HTML writer. When the writer receives the arrays, it can ask each one for the .length property to know how large each one is.
Not directly related to the question but you should see this:
Google techtalks about javascript
Maybe it will enlighten you :)
Couple of things about your question. First you should use '!=' instead of '!==' to check inequality. Second I am not sure why you are doing decreasing counts by 2, suggests to me that there may be duplicates in the array?! In any case your logic was wrong which was corrected by Jarrett later, but that was not a totally correct/complete answer either. Read ahead.
Your task sounds like "Given two set of arrays i1 & i2 to find i1 {intersection} i2 and i1{dash} {UNION} i2{dash}) (Group theory notation). i.e. You want to list common elements in newArray and uncommon elements in newArray2.
You need to do this.
1) Remove duplicates in both the arrays. (For improving the program efficiency later on) (This is not a MUST to get the desired result - you can skip it)
i1 = removeDuplicate(i1);
i2 = removeDuplicate(i2);
(Implementation for removeDuplicate not given).
2) Pass through i1 and find i1{dash} and i1 {intersection} i2.
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++)
{
var found = false;
for (var j = 0; j < i2.length; j++)
{
if (i1[i] == i2[j])
{
found = true;
newArray.push(i1[i]); //add to i1 {intersection} i2.
count++;
break; //once found don't check the remaining items
}
}
if (!found)
{
newArray2.push(i1[i]); //add i1{dash} to i1{dash} {UNION} i2{dash}
count2++;[
}
}
3) Pass through i2 and append i2{dash} to i1{dash}
for(var x=0; x<i2.length; x++)
{
var found = false;
//check in intersection array as it'd be faster than checking through i1
for(var y=0; y<newArray.length; y++) {
if( i2[x] == newArray[y])
{
found = true;
break;
}
}
if(!found)
{
newArray2.push(i2[x]); //append(Union) a2{dash} to a1{dash}
count2++;
}
}
writeHTML(count,count2, newArray, newArray2);
I have a feeling that this has to do with your second comparison using "!==" instead of "!="
"!==" is the inverse of "===", not "==". !== is a more strict comparison which does not do any type casting.
For instance (5 != '5') is false, where as (5 !== '5') is true. This means it's possible that you could be pushing to both arrays in the nested loop, since if(i1[i] == i2[j]) and if(i1[i] !== i2[j]) could both be true at the same time.
The fundamental problem here is that a pair of nested loops is NOT the right approach.
You need to walk a pointer through each dataset. ONE loop that advances both as needed.
Note that figuring out which to advance in case of a mismatch is a much bigger problem than simply walking them through. Finding the first mismatch isn't a problem, getting back on track after finding it is quite difficult.

Categories

Resources