JavaScript splice() not working - javascript

for(var i = 0; i < this.phrases.length; i++) {
console.log('sort ' + this.phrases[i]);
console.log('sort length' + this.phrases.length);
if(this.phrases[i] == null) {
var s = this.phrases.splice(i, 1);
console.log('splice ' + this.phrases[i]);
console.log('splice length ' + this.phrases.length);
}
}
I have an array (this.phrases). I made the phrase that I want to remove equal to null in another section. The first log prints null, the second log also prints null. Why is it not getting spliced? This is also sometimes the last item in an array. Are you not able to splice an array with only one element? The same thing happens, however if it is not the last item in this.phrases.
Edit: s also does not seem to get set to any value.
Edit: The two length logs I added print the same number.
Edit: That's not actually true. Weird things are happening with the lengths, probably not involving this section of code. I just want to know if I'm using splice() correctly.

Switch these two lines:
var s = this.phrases.splice(i,1);
console.log('splice ' + this.phrases[i]);
To this:
console.log('splice ' + this.phrases[i]);
this.phrases.splice(i, 1);
i--;

const indexOfValue = treeSelectDataTemp.findIndex((item: any) => item.value === deleteIndexId[d]);
console.log(" ########### deleted indexOfValue ", indexOfValue);
if (indexOfValue !== -1) {
treeSelectDataTemp.splice(indexOfValue, 1);
}

Related

Printing elements of an array

I'm trying to print the elements of an array. When I try a very basic W3 Schools Example, it works perfectly, but when I take the loops and variables and modify it to my application, it's acting oddly.
Basically, I have a user input. That input is pushed into an empty array. I'm using a loop to cycle through that array and print each element to the screen. If you see the pic, it's not printing correctly. I've tried three different versions of loops and all aren't printing the way I expect.
I instantiate the charNotInWordArr out of the function.
var charNotInWordArr = [];
Relevant JS:
charNotInWordArr.push(userInput);
console.log("the char is not in the word");
console.log("the char is " + userInput)
for (var i = 0; i < charNotInWordArr.length; i++) {
$('#wrongGuessList').append("<li class='list-group-item'>" + userInput[i] + "</li>");
}
Other for loops gone wrong:
$.each(charNotInWordArr, function(userInput) {
$('#wrongGuessList').append("<li class='list-group-item'>" + userInput[i] + "</li>");
});
$.each(charNotInWordArr, function(index, value) {
$('#wrongGuessList').append("<li class='list-group-item'>" + value[i] + "</li>");
});
It's printing like this:

How should I properly assign a key and value pair?

JavaScript newbie. My code is working BUT I'm still getting this alert:
should_properly_assign_key_and_value_pair, Expected 'string' to be
'object'.
Not sure how update current code to address this issue. Any advice? Thank you!
function transformFirstAndLast(array) {
var result = '';
for (var i = 0; i < array.length; i++) {
result = (array[0] + ": " + array[array.length-1]);
return result;
}
}
console.log(transformFirstAndLast(['Kevin','Bacon','Spacey']));//Kevin : 'Spacey'
Since it is expecting a key/value pair. Create a new object and set the data.
Change
result = (array[0] + ": " + array[array.length-1]);
to
var result = {};
result[array[0]] = array[array.length-1];
return result;
It's hard to understand what your code wants to do? The current code will always return the first element and the last element in the array with a ':' in middle, regardless how many other elements in the array. Is that your intention? If yes, I think you don't need to the loop, right? just return array[0] + ':' + array[arraly.length - 1] does the job for you..
If your intention is to concatenate the elements in the array, your code need to be revised.

Javascript: What is the full purpose of this array splice?

I'm going through a Javascript course and its challenges. I don't have a question about how to do this particular challenge but I was going through the code in my mind to make sure I understood all of it and I ran into a question.
var strength = true;
var fear = false;
var pack = {
foodPouch: ['carrot', 'mystery meat', 'apple', 42],
addFood: function(foodItem) {
this.foodPouch = this.foodPouch || [];
this.foodPouch.push(foodItem);
},
gobbleFood: function(foodItem) {
return(this.foodPouch.indexOf(foodItem) >= 0) ?
this.foodPouch.splice(this.foodPouch.indexOf(foodItem), 1)[0] :
alert('Your pack lacks ' + foodItem);
},
feedBird: function(birdFood) {
for (var i = 0; i < this.foodPouch.length; i++) {
if (this.foodPouch[i] == birdFood) {
alert('Feed beggar bird ' + this.foodPouch[i]);
}
}
}
};
pack.feedBird('42');
My question is with this line:
return(this.foodPouch.indexOf(foodItem) >= 0) ?
this.foodPouch.splice(this.foodPouch.indexOf(foodItem), 1)[0] :
alert('Your pack lacks ' + foodItem);
Why does the first ternary action that splices the array end with [0], which I believe makes that whole action into the value of the spliced array? I can see if you wanted to declare it as some kind of variable, but it seems like the main purpose is just to splice it off. Does it matter if that [0] is there at all?
splice removes elements from an array, then returns an array containing the removed elements.
In this case, the gobbleFood function is checking for the presence of a particular item (using indexOf) and is removing and returning the first instance of it if it exists in foodPouch.
The removal is done using splice, and since splice returns an array of items removed, even if it's only removed 1 item as in this case, it's necessary to use [0] as an indexer to get at the single item that was removed.
return(this.foodPouch.indexOf(foodItem) >= 0) ?
this.foodPouch.splice(this.foodPouch.indexOf(foodItem), 1)[0] :
alert('Your pack lacks ' + foodItem);
This statement translated to English says:
Return "the zeroth element of the 'returned array' after removing the foodItem" if it exists there. Or just display a message if it is not.
Or I can write it in this manner in JS:
if (this.foodPouch.indexOf(foodItem) >= 0) {
var removedItems = this.foodPouch.splice(this.foodPouch.indexOf(foodItem), 1);
return removedItems[0];
};
else
alert('Your pack lacks ' + foodItem);

Populate a prompt with elements of an array and number them off

(Stack Overflow doesn't have a tag for 'prompt' so I have used alert as I am guessing it is similar enough to attract the right answerers.)
Hello,
I am currently making a JavaScript-based game for an assignment at university. I am usually pretty good with problem solving but have been stumped by this issue.
To explain, I have an array which names the possible armour slots the player can pick. In any order these can be picked, and each time the choice gets pushed to a second array which handles what has already been picked (and in what order) and that item gets spliced from the original array. There is a while loop which runs through until all 3 have been picked.
var armourSlotToPick = ["Head", "Chest", "Legs"],
armourSlotPicked = [],
armourLoop = 1,
indexArmour = 0;
function numInArray() {
indexArmour++;
return (indexArmour + ". " + armourSlotToPick[indexArmour - 1] + "\n");
}
function armour() {
while (armourLoop < 4) {
var armourPick = prompt("Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray));
if (armourPick == 1) {
armourSlotPicked.push(armourSlotToPick[0]);
armourSlotToPick.splice(0,1);
} else if (armourPick == 2) {
armourSlotPicked.push(armourSlotToPick[1]);
armourSlotToPick.splice(1,1);
} else if (armourPick == 3) {
armourSlotPicked.push(armourSlotToPick[2]);
armourSlotToPick.splice(2,1);
} else {
alert("Invalid choice, you suck");
break;
}
armourLoop++;
}
}
I know it probably wouldn't be possible to do the whole return in numInArray() to the prompt, but it shows some working.
Now the problem: I got it working so that each item in the array was numbered (var armourSlotToPick = ["1. Head", "2. Chest", "3. Legs"],) but as you could see, if the player chose 2, then the next time it would show "1. Head (new line) 3. Legs" and when the player chooses 3, a problem would occur, as they were really meant to choose 2. How is it possible to number the items in the array, in a prompt?
I'm possibly over thinking this but I have suffered for a few hours now.
I thank you in advance for any insight you may have,
Daniel.
EDIT: Solved.
Below is the end result, a slight variation from the edited answer from Jonathan Brooks.
var armourSlotToPick = [null, "Head", "Chest", "Legs"]
var armourSlotPicked = [null];
var armourLoop = 1;
function armour() {
while (armourLoop < 4) {
var message = "Pick an armour slot to generate an item for:\n";
for (var i = 0; i < armourSlotToPick.length; i++) {
if (armourSlotToPick[i] !== null) {
message += "" + i + ". " + armourSlotToPick[i] + "\n";
}
}
var armourPick = prompt(message);
if (armourPick > armourSlotToPick.length-1 || armourPick < 1) {
alert("Invalid choice, you suck");
} else {
var insert = armourSlotToPick.splice(armourPick, 1);
armourSlotPicked.push(insert);
}
armourLoop++;
}
armourSlotPicked.splice(0,1);
}
armour();
alert(armourSlotPicked.join("\n"));
I thank all that have contributed to this discussion and the end result, and I hope this is a good example for future problems people may have similar to this.
Check out my fiddle, I think I have a working solution.
What you really want to be using are Object Literals with your own indexing (starting from 1) - if it were me, I would create my own way to iterate over this custom indexing by adding a method to the Object's prototype, but I digress.
You're overcomplicating your code by using a while loop, and that large bulk of if statements is unnecessary: instead, all you need is some basic validation on the input and then you can just trust whatever input passes this validation. That is demonstrated here:
if ( armourPick > armourSlotToPick.length || armourPick < 1 ) {
alert("Invalid choice, you suck");
}
else {
armourSlotPicked.push( armourSlotToPick[armourPick-1] )
alert (armourSlotPicked[armourSlotPicked.length-1].value);
}
Read my code carefully, and you should get a better understanding of how to deal with certain issues.
EDIT:
As per your request, I think I have a solution that suits your needs. Basically all you have to do to have the arrays "start" at an index of 1 is to fill the zeroth element with a null value, like so:
var armourSlotToPick = [null, "Head", "Chest", "Legs"]
var armourSlotPicked = [null];
You just have to remember to take this null object into account in your code, for example:
if (armourSlotToPick[i] !== null) {
message += "" + i + "\n";
}
The indices will update automatically. See this updated fiddle for more details.
use structures / objects as content in the array, instead of just values.
the basic concept:
armourSlotPicked.push({ "key": 1, "value":armourSlotToPick[1]})
alert("value: " + armourSlotPicked[0].value)
alert("key: " + armourSlotPicked[0].key)
edit: responding to comments can take some space.
IMHO a prompt is the completely wrong tool for this, since most browsers would ask the user permission to prevent multiple popups, and since a promt can only return 1 piece of information, you can only ask for 1 thing per popup. Instead you ought to use a div element, with checkboxes for each information..
That being said it can easily be used in a promt.
The prompt is just a built in function, that takes a string as an argument (which is shown as text in the popup) and returns a string with the users input.
what does the magic for you is in fact this:
array.foreach(): The forEach() method executes a provided function once per array element.
in your case that means it calls a function that returns a string for each element in the array, and concatenates the strings.
in the old days you would have written this:
var messageText= "Pick an armour slot to generate an item for:\n"
for(var i = 1; i < armourSlotToPick.length; i++){
messageText += i + ". " + armourSlotToPick[i- 1] + "\n";
}
var armourPick = prompt(messageText);
but in this modern age, you define a printing function, and use it to generate the loop:
function numInArray() {
indexArmour++;
return (indexArmour + ". " + armourSlotToPick[indexArmour - 1] + "\n");
}
//more code before we get to where the function is used....
indexArmour = 0;
var messageText = "Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray);
var armourPick = prompt(messageText);
or in a single line as in your code:
indexArmour = 0; //you forgot this - otherwise the list will only be complete once?
var armourPick = prompt("Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray));
It produces the same output, because it does the same thing, its just written very differently!
If the array holds "object literals" instead of simply values, as I suggest, the old fashioned code would look something like this:
function contains(a, value) {
try{
for (var i = 0; i < a.length; i++) {
if (a[i].value == value) {
return true;
}
}
}
catch(err) {
// do nothing
};
return false;
}
and later..
for(var j = 0; j < 4; j++){
for(var i = 0; i < Math.min(armourSlotToPick.length); i++){
if( contains(armourSlotPicked, armourSlotToPick[i- 1]) )
continue;
var messageText = "Generate an item for armour in slot: " + i + "\n"
messageText += armourSlotToPick[i- 1] + "\n";
}
var armourPick = prompt(messageText);
if (armourPick > 0 && armourPick < armourSlotToPick.length) {
armourSlotPicked.push({"key":j, "value":armourSlotToPick[armourPick]);
}
...
}
//now we have an array that holds information about when what was picked..
or something along those lines.. this is bt.w completely untested, it's just for illustration
You want to use the array index to number your items. Since your numbers are one-based and the index is zero-based, you will need to convert between the two when outputting and interpreting the response.
This approach will also allow you to eliminate all but two of the cases in your if-else statement.

Am I loopy or is it localstorage...?

My goal: To clean up localstorage, by removing previously used items with a for loop.
Usually, I have a number of items, like so:
order-1356666288243 => {"cartID":2713329701836,"productName"...
order-1356666288243 => {"cartID":2713329701836,"productName"...
When I check how many items there are altogether, I get the correct zero-based amount:
console.log( localStorage.length );
Even when I do a for loop to write out the key and values, and console.log() a few other things, all is well:
for(var i=0, len=localStorage.length; i<=len; i++) {
var key = localStorage.key(i);
var value = localStorage[key];
console.log(key + " => " + value);
if(key != '' && key != null){
console.log( key.indexOf('order-') );
console.log(i + '. Key: ', key);
if(key.indexOf('order-') != -1){
console.log('The key to be removed is: ', key.toString());
localStorage.removeItem(key.toString());
}
}
console.log(i + ': ' + len);
}
Everything pretty much does what one would expect. However, this line executes only once when I run the script:
localStorage.removeItem(key);
or
localStorage.removeItem(key.toString());
In fact, I have to run the entire script as many times as there are items. So if I have, say 3 items, I need to run the loop 3 times to get rid of each item.
I'm perplexed: Where did I go wrong? All the console.log() stuff shows up 3 times (if I have 3 items and run the for loop once) . Out of despair, I even changed i < len to i >= len, but that doesn't solve the problem either.
Anyone?
The problem is that you are modifying a collection while you are traversing it. Always be careful when you do this.
In this particular case, the length of localStorage changes when you remove an item, so you end up skipping items.
You should either traverse localStorage backwards (last item to first item), or better yet you should do this in two passes: one pass to collect the keys to remove, and another pass to remove them:
Object.keys(localStorage)
.filter(function(key){return key.indexOf('order-')===0})
.forEach(localStorage.removeItem, localStorage);
Or if you need this to work in IE8 or FF3.x:
var delkeys = [], key, i, len;
for (i=0,len=localStorage.length; i<len, key=localStorage.key(i); i++) {
if (key.indexOf('order-')===0) {
delkeys.push(key);
}
}
for (i=0,len=delkeys.length; i<len, key=delkeys[i], i++) {
localStorage.removeItem(key);
}
I think the problem is that when you remove an item, it changes the length of the local storage. Try iterating from the length-1 down to 0 instead of from 0 up to the length. (By the way, the loop condition should have been i < len, not i <= len. With my suggestion, of course, it should be i >= 0.)
The loop should count down to prevent problems with deleted keys altering storage length. Try this for loop instead:
for( var i = localStorage.length; i--;){
//make sure to remove references to len in your code
}

Categories

Resources