deleting an item from array and add it to another array - javascript

I'm trying to delete an item from an array and add it to another array. The array states consists of a list of 50 states. User needs to enter the name of a state and the state must get deleted from states array and get added to the array correctState. Here is my code
function searchString()
{
var total = 50;
var string = document.getElementById("txtState").value;
var element = document.getElementById("status");
for (i=0; i < states.length; i++)
{
if(states[i].toUpperCase() == string.toUpperCase())
{
count = count + 1;
//element.innerHTML = "CORRECT!!!"
addElem = states.splice(i,1);
correctState.push(addElem);
/*for (j=0; j < correctState.length; j++)
{
if(correctState[j].toUpperCase() == string.toUpperCase())
{
element.innerHTML = "Already Submitted. Try another State";
}
}*/
}
document.getElementById("score").innerHTML = count +"/"+ total;
document.write(states);
document.write(correctState);
}
}
Enter State : <input type="text" name="txtState" id="txtState"><span id="timer"></span><br /><span id="status"></span>
<button type="button" name="btnPlay" id="btnPlay" accesskey="s" onClick="searchString()"><u>S</u>ubmit</button>
I'm not able to achieve what I need. I'm new to javascript and need help.

Re these lines:
addElem = states.splice(i,1);
correctState.push(addElem);
splice doesn't return the element that you remove, it returns an array of those elements. So your code is pushing array instances onto correctState. I'd do this:
correctState.push(states[i]); // First push the matching state onto `correctStates`
states.splice(i,1); // ...then remove it
Alternately, you could do it in the order you showed, you just have to get the removed element out of the array you get back
addElem = states.splice(i,1);
correctState.push(addElem[0]);
// Here -----------------^^^
but again, I'd do it by pushing first, then removing.
Separately, I'd use the debugger built into your browser to single-step through that code and watch it run. I suspect you'll find that you want to move some things around, and you almost certainly want to stop looping once you've found that string matches something in the array.

My guess is that it's the fact that you're modifying your states array while you are still enumerating.
So say you're states array is [AR, LA, CT] and the user entered LA. So your for loop goes like this
i = 0 (length is 3 so i < 3)
string not found
i = 1 (length is 3 so i < 3)
string found, remove it from states
i = 2 (length is 2 so i < 2 fails and there's no final loop)
What you probably want is just something like this
function moveAllInstancesBetweenArrays(val, source, destination) {
var indexOfVal = source.map(function(s) { return s.toUpperCase() })
.indexOf(val.toUpperCase());
if(indexOfVal == -1)
return;
source.splice(indexOfVal, 1);
destination.push(val);
moveAllInstancesBetweenArrays(val, source, destination); //continue until all matching are moved
}
moveAllInstancesBetweenArrays(yourSearchVal, states, correctStates);

Related

Can't get stable result with copying random values from array to an object

So I'm in process of creating a bot for a tournament and I got stuck on the part where I want to split players in pairs for play-off-style tournament. I just want to take 2 random players, get them from an array and write it as a value to a key as a round id for an object. Also I should not use those players again in the pair, so need to delete them or smth.
Here's the code:
var users = inc.funcs.getDatabase() //Getting a raw array of users (using my func that's basically a simplified fs.readFileSync func)
var tournamentPairs = new Object() //Object initialization
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * (users.length + 1)) //Randomizing 2 indexes
var second = Math.floor(Math.random() * (users.length + 1))
var player1 = client.users.get(users[first]) //Getting the players by id
var player2 = client.users.get(users[second])
tournamentPairs[id++] = [player1.id, player2.id] //Writing to the object
users.splice(first, 1) //Deleting user's indexes from the array to not use them anymore.
users.splice(second, 1)
}
console.log(tournamentPairs)
It works perfectly on the outside, but has a bad habit of duplicating users and I once could have a gamergod98 vs gamergod98 for example. I tried console.log this crap but it often get an error when trying to console.log player2 because it's undefined for some reason. If I try to print users[second] I get undefined though it never happened for the first player. So I tried different ways to prevent situations like this: first == second. Long story short it didn't help much.
I have 9 days 'till tournament starts, any ideas on how to improve this code?
You are getting undefined because you are going out of bounds of your users list. For a list of length the last element is list[length-1], but you are generating random numbers up to length.
To fix duplicate users, remove the first selected user from the list before selecting the second one (or for a less destructive approach, mark already selected users).
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * users.length)
var player1 = client.users.get(users[first])
users.splice(first, 1)
var second = Math.floor(Math.random() * users.length)
var player2 = client.users.get(users[second])
users.splice(second, 1)
tournamentPairs[id++] = [player1.id, player2.id]
}
Create a collection of used indexes and then if first or second are in used indexes then continue
var usedIndices = [] ;
if (usedIndices.indexOf(first) >= 0 ||
usedIndices.indexOf(second) >= 0) {
continue;
} else {
usedIndices.push(first);
usedIndices.push(second);
}
Put the usedIndices variable before for loop and the if else block inside loop after second

Using Javascript Array Filter method to apply logic [duplicate]

I have search through quite a lot of questions here, but havent found one that i think fits my bill, so if you know of one please link to it.
I have an array that i want to search through for a specific number and if that number is in the array, i then want to take an action and if not then another action.
I have something like this
var Array = ["1","8","17","14","11","20","2","6"];
for(x=0;x<=Array.length;x++)
{
if(Array[x]==8)
then change picture.src to srcpicture1
else
then change picture.src to srcpicture2
}
but this will run the lenght of the array and end up checking the last element of the array and since the last element is not 8 then it will change the picture to picture2.
Now i can see why this happens, i just dont have any ideas as to how to go about checking if an array contains a specific number.
Thanks in advance.
What you can do is write yourself a function to check if an element belongs to an array:
function inArray(array, value) {
for (var i = 0; i < array.length; i++) {
if (array[i] == value) return true;
}
return false;
}
And the just do:
var arr = ["1","8","17","14","11","20","2","6"];
if (inArray(arr, 8)) {
// change picture.src to srcpicture1
} else {
// change picture.src to srcpicture2
}
It's a lot more readable to me.
For extra points you can add the function to the array prototype like so:
Array.prototype.has = function (value) {
for (var i = 0; i < this.length; i++) {
if (this[i] === value) return true;
}
return false;
};
And then the call would be
if (arr.has(8)) // ...
Pushing this even further, you can check for indexOf() method on array and use it - if not - replace it with the code above.
P.S. Try not to use Array for a variable name, since it's reserved for the actual array type.
use this
http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/IndexOf
ie version
https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/IndexOf#Compatibility
Why don't just you abort the loop when you find the right number :
for(x=0;x<=Array.length;x++)
{
if(Array[x]==8) {
//change picture.src to srcpicture1
break;
}
}
You could sort the array first then check the array only up to the point at which a number would be in the array, were it to exist.
If you have unique keys and a faster retrieval is what you care about a lot, you can consider using a map instead of an array (if there's a hard-bound case of using an array, then it won't work of course). If using a map, you just check "if( num in arr ) ".

Nested 'for' loop - array undefined

I am working on a JS where I want to create a simple game that starts by chosing number of players, name of each player and whether a player is a dealer or not. There can be only one dealer for each game:
function player(playerName, playerDealer) {
this.playerName = playerName;
this.playerDealer = playerDealer;
}
var playerNumber = prompt('Nr of players?');
var playersArray = [];
for (i = 0; i < playerNumber; i++) {
var j = i + 1;
var dealerAssigned = false; // control variable to check whether dealer has been assigned
var inputName = prompt('Name of player nr ' + j);
var inputDealer = prompt('Is player ' + inputName + ' also a dealer? (yes/no)');
playersArray[i] = new player(inputName, inputDealer);
for (k=0;k<playerNumber;k++){ // I want to go through the players array to check if dealer has been assigned
if (playersArray[k].playerDealer == 'yes') {
dealerAssigned=true;
break;
};
};
if(dealerAssigned){ //if dealer has been assigned, don't add the current player to the array and continue with the next iteration
alert("already assigned");
continue;
};
};
I need to include a simple test into the loop that would check if the dealer has been appointed. If so, I want the script only to alert 'already assigned' and skip to the next player. But I am constantly getting the following error
TypeError: playersArray[k] is undefined
Can anybody explain why is it undefined?/What am I doing wrong?
The bug you're specifically asking about appears to me to be that you're iterating over undefined array values, as the error you're getting suggests.
You're getting the number of players you want in line
var playerNumber = prompt('Nr of players?');
Then, you proceed to have two iterations (one nested in the other), in which the inner loop is trying to access values that haven't yet been assigned since the outer loop hasn't gotten there yet:
for (i = 0; i < playerNumber; i++) {
playersArray[i] = new player(inputName, inputDealer);
for (k=0; k < playerNumber; k++) {
if (playersArray[k].playerDealer == 'yes') {
...
}
}
}
It appears to me that the logical error here is the nested loop. I recommend just initializing all players in one loop, then verify that all players have an assigned dealer afterward.
I should add that I'm being intentionally myopic here and focusing very narrowly on the question asked and overlooking other issues I see.
Your for loop inside a for loop is iterating over an array that hasn't been filled yet.
First iteration playersArray[j] = new Player(...) makes the array [Player] or an array of one element! Yet the second loop is looking for an array of many elements. once you look for playersArray[1] but there is only playerArray[0] you get undefined and so undefined.playerDealer causes a TypeError.
`This is your structure stipped-down:
for (i = 0; i < playerNumber; i++) {
playersArray[i] = new player(inputName, inputDealer);
for (k=0;k<playerNumber;k++)...{
//anything with index k > i is undefined, since your outer loop
//hasn't initialized it yet.
}
}
It seems that your i-loop is trying to insert elements for the size of the array to be, but your k-loop is trying to also access the entire array instead of just the initialized portions. Limit this to for (k=0; k<i+1 ;k++) so you only check the previously initialized values of you playersArray

How to compare Array value to result of 'for' loop in javascript

I have an empty array (called zoomthumbsarray) which gets values pushed to it whilst a 'for' loop is running. This 'for' loop is checking if a thumbnail image is present in the backend against the particular product the user is viewing. If there is an image it gets added into a vertical slider. The current issue is there are non colour specific images (like lifestyle shots) that are being added into the slider multiple times.
So I need to check if the image found in the for loop is currently stored in the array. If it is present, the image has already been generated and I don't want it to get pulled into the slider again. If it hasn't then the image will get added.
Below is the code I am working on. I would presume indexOf would be used but can't get this to work.
Any help would be really appreciated.
var zoomthumbsarray = [] // Empty array which gets populated by .push below during loop
for (var i = 0; i < storeImgsArr.length; i++) { // storeImgsArr finds the quantity of attributes present against the product. This loops and increments counter if there is another attibute image
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) { // Loop and increment counter if there is a Large image
zoomthumbsarray.push(storeImgsArr[i].images.imgS[e].slice(-16)); // Slices off last 16 characters of image path i.e. _navy_xsmall.jpg or 46983_xsalt1.jpg and pushes this into 'zoomthumbsarray' array
// if statement sits here to build the html to add the image to the slider
}
}
zoomthumbsarray = [] // Resets array to zero
ANSWER
As answered by Chris I used $.unique to only keep unique values in the array.
Then wrap an if statement around the code to build the thumb image html if the array === 0 or if the current image isn't already in the array.
Updated code below:
var zoomthumbsarray = [] // Empty array which gets populated by .push below during loop
for (var i = 0; i < storeImgsArr.length; i++) { // storeImgsArr finds the quantity of attributes present against the product. This loops and increments counter if there is another attibute image
if (zoomthumbsarray === 0 || zoomthumbsarray.indexOf(storeImgsArr[i].images.imgS[e].slice(-16)) < 0) { // If statement is true if array === 0 or if the current image isn't already in the array
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) { // Loop and increment counter if there is a Large image
zoomthumbsarray.push(storeImgsArr[i].images.imgS[e].slice(-16)); // Slices off last 16 characters of image path i.e. _navy_xsmall.jpg or 46983_xsalt1.jpg and pushes this into 'zoomthumbsarray' array
zoomthumbsarray = $.unique(zoomthumbsarray); //Keeps only unique elements
// if statement sits here to build the html to add the image to the slider
}
}
}
zoomthumbsarray = [] // Resets array to zero
Some cheap and dirty ideas:
Using underscore/lodash:
zoomthumbsarray = _.uniq(zoomthumbsarray); //Keeps only unique elements
jQuery has one as well:
zoomthumbsarray = $.unique(zoomthumbsarray); //Keeps only unique elements
then you loop through the array and build HTML.
Update:
There's something a bit odd about the rest of the JS. Might this work (if you're using a new enough browser)?
var zoomthumbsarray = [];
storeImgsArr
.map(function(item) { return item.images.imgS; })
.forEach(function(imgS) {
zoomthumbsarray = zoomthumbsarray.concat(imgS.map(function(imagePath) {
return imagePath.slice(-16);
}));
});
zoomthumbsarray = $.unique(zoomthumbsarray);
I have tried indexOf (see first if statement below) but this doesn't work.
As #elclanrs said, indexOf does return the index in the array not a boolean. You only will need to see if it's >= 0 to test whether an image is already contained in the array.
var zoomthumbsarray = [];
for (var i = 0; i < storeImgsArr.length; i++) {
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) {
var image = storeImgsArr[i].images.imgS[e].slice(-16);
if (zoomthumbsarray.indexOf(image) < 0) { // not yet in the array
zoomthumbsarray.push();
// and build the html to add the image to the slider
}
}
}
If you have really lots of images and notice this starts slowing the page down, then there are too many images in your page anyway. No, joke aside; …then check the optimisation by #Ivey.
instead of using an array you can use an object to store the images as keys and a dummy value (possibly true). then you can extract the keys from this object.
var images = {};
for (var i = 0; i < storeImgsArr.length; i++) {
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) {
images[storeImgsArr[i].images.imgS[e].slice(-16))] = true;
}
}
var zoomthumbsarray = [];
for(var k in images) {
zoomthumbsarray.push(k);
// build the html to add the image to the slider
}
EDIT: Added build html comment

How can I pick data out of an array in a object and insert it into another array in an object in Javascript?

I have variable qstore that's has an ans array containing a list of responses. The field named r is used to hold the response data (true or false) and is stored in an array called ans
qstore: {"id":2,
"qId":2,
"ans":[{"r":true},
{"r":true},
{"r":false},
{"r":false},
{"r":false}]}
Another variable qview:
qview: {"problemId":2,
"questionId":1,
"answer":null,
"text":"xx",
"answers":[{"answerId":1,
"response":false},
{"answerId":2,
"response":false},
{"answerId":3,
"response":false},
{"answerId":4,
"response":false},
{"answerId":5,
"response":false}]}
What I need to do is IF there is an array called ans in qstore (there may not be one) then I need to take the answer responses field r and use that to update the answers response field in the qview object. Note that the qview and qstore if they do have answers will always have the same number of answers.
Can anyone tell me a simple way that I can do this?
What I need to do is IF there is an array called ans in qstore (there may not be one) then I need to take the answer responses field r and use that to update the answers response field in the qview object. Note that the qview and qstore if they do have answers will always have the same number of answers.
// assuming `qstore`, `qview`
var i, j, ans = qstore.ans;
if (ans) { // if qstore has non-falsy ans
qstore: for (i = 0, j = 0; i < ans.length; ++i) { // loop over ans
for (; j < qview.answers.length; ++j) { // look in qview
if (qview.answers[j].answerId === i + 1) { // qview has already
qview.answers[j].response = ans[i].r;
continue qstore; // go back to looping ans
} else if (qview.answers[j].answerId <= i) { // qview needs new
break; // get out of qview loop
}
} // if we reach here then qview didn't have an entry for this item
qview.answers.splice(j, 0, { // insert new entry
'answerId': i + 1,
'response': ans[i].r
});
}
}
Just simply loop over the qstore.ans array (if it exists) and set the respective value in qview.
if(qstore.hasOwnProperty('ans')){
for(var i = 0, len = qstore.ans.length; i < len; i++){
qview.answers[i].response = qstore.ans[i].r;
}
}
JavaScript has an multiple ways to check if a key exists in an object: in and Object.hasOwnProperty. The difference between the two is that in also returns true if the key is found in the prototype chain of your object.
Now it appears the id's of your response are 1-indexed, but that doesn't matter if we iterate over the index of its position in the array itself:
if ('ans' in qstore) {
for (var i = 0; i <= qstore.ans.length; i++) {
qview.answers[[i].response = qstore.ans[i].r
}
}
There's also a nicer forEach available, if you're not expecting to support IE8 and earlier, or are prepared to insert a "shim":
if ('ans' in qstore) {
qstore.ans.forEach(function(element, index) {
element.response = qstore.ans[index].r
})
}
The most simple solution.
This way it will execute only if you have at less, 1 register on ans array, i see that the solutions above do not verify if the ans array have registers, so i think it is the right one for your case.
Here is the code:
if (qstore.ans != null){
if (qstore.ans.length > 0){
for (i=0;i<qstore.ans.length);i++){
qview.answers[i].response = qstore.ans[i].r;
}
}
}

Categories

Resources