The problem is the - operator does not working (in 8th line). See my code below:
array = [0,0,0,0,3,0,0,0,0],
n = 0;
for(var i = 0; i < array.length; i++){
if(n < 9){ //the "n" variable there's only for don't crash the browser with a infinite loop
if(array[i] == 3){
array[i] = 0;
array[i - 1] = 3; //I believe that here is the problem
}
}
n++;
}
console.log(array);
So... I want to move the "3" value to the beginning of the array. But it only work if I use the + operator(in 8th line). Consequently, if I use the + one, the "3" value goes to the end of the array.
Anyone know why the - operator does not working in this case and the + works?
If you change line 8 to:
array[i+1] = 3;
then the number 3 will go all the way to the end of the array (well, beyond the end of the array and I'll be damned to find out what Javascript does then!). This is because the loop traverses the array in increasing order and the position i+1 will be checked right next.
On the other hand, with your current line 8, number 3 goes one position backwards (which has already been checked), so it doesn't go all the way to the beginning of the array, just one position. If you want it to go to all the way in the same fashion, you should reverse the loop (make it traverse the array in descending order of the position i).
What do you think happens when i is 0 and you do - 1?
In your first iteration of the loop, when i is zero, (i - 1) is -1, so you're trying to access array[-1], which is invalid.
Okay, instead of answering "Anyone know why the - operator does not working in this case and the + works?", I will answer what I think is the real question, as stated in the original post: I want to move the "3" value to the beginning of the array. I think this does what is desired:
var array = [0,0,0,0,3,0,0,0,0];
var first_val = 3;
var index = array.indexOf(first_val);
if (index > 0) {
array.splice(index, 1);
array.unshift(first_val);
}
console.log(array);
Inspired by this.
I want to move the "3" value to the beginning of the array
Use the correct answer provided in here. Then use .indexOf() to move it.
Array.prototype.move = function (old_index, new_index) {
if (new_index >= this.length) {
var k = new_index - this.length;
while ((k--) + 1) {
this.push(undefined);
}
}
this.splice(new_index, 0, this.splice(old_index, 1)[0]);
return this; // for testing purposes
};
var array = [0,0,0,0,3,0,0,0,0];
var result = array.move(array.indexOf(3),0);
console.log(result);
JSFiddle Demo
Related
I am a beginner in code world. I have troubles understanding recursion in JavaScript especially when it needs two or more looping. Like I want to print rectangle using recursion. I don't know completely how to make a base case, condition when it still executed. For examples, these codes below I use to print rectangle or holey rectangle.
function box(num) {
for (let i = 0; i < num; i++) {
let str = ''
for (let j = 0; j < num; j++) {
str += '*'
}
console.log(str)
}
}
box(5)
function holeBox (num) {
for(let i = 0; i < num; i++){
let str = ''
for(let j = 0; j < num; j++){
if(i == 0 || i == num -1 || j == 0 || j == num - 1) {
str += '*'
} else {
str += ' '
}
}
console.log(str)
}
}
holeBox (5)
Please help me to understand recursion, an explanation would be great. My goals are not only to solve those codes but also to understand how recursion works. I've searched there's no good source to learn recursion, or I just too dumb to understand. Thanks in advance
To understand how recursion works, just think of how you can split up what you want to accomplish into smaller tasks, and how the function can complete one of those tasks, and then call itself to do the next- and so on until it is finished. I personally don't think printing boxes is the best way to learn recursion, so imagine you wanted to search an array for a specific value; ignore JavaScript's indexOf()/find() functions or similar for now.
To do this using loops, its easy, just iterate over the array, and check every value:
//Returns the index of the first occurrence of a value in an array, or -1 if nothing is found
function search(needle, haystack) {
for (let i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) return i;
}
return -1;
}
Doing this using recursion is easy as well:
function recursiveSearch(needle, haystack, i) {
if (i > (haystack.length - 1)) return -1; //check if we are at the end of the array
if (haystack[i] == needle) return i; //check if we've found what we're looking for
//if we haven't found the value yet and we're not at the end of the array, call this function to look at the next element
return recursiveSearch(needle, haystack, i + 1);
}
These functions do the same thing, just differently. In the recursive function, the two if statements are the base cases. The function:
Tests if the current element is out of bounds of the array (meaning we've already searched every element), and if so, returns -1
Tests if the current element is what we're looking for, and if so, returns the index
If neither of the statements above apply, we call this function recursively to check the next element
Repeat this until one of the base cases kicks in.
Note that recursive functions are usually called from other helper functions so that you don't have to pass the initial parameters to call the function. For example, the recursiveSearch() function above would be private, and it would be called by another function like this:
function search(needle, haystack) {
return recursiveSearch(needle, haystack, 0);
}
so that we don't have to include the third parameter when we call it, thus decreasing confusion.
Yes, even your box code can be turn into recursion but I don't think it will help you understand the concept of recursion.
If you really have to:
function getBox(arr, size) {
let length = arr.length;
if (length == size)
return arr; // recursion stop rule - if the size reached
for (let i = 0; i < length; i++)
arr[i].push("*"); // fill new size for all row
arr.push(new Array(length + 1).fill("*")); // add new row
return getBox(arr, size); // recursive call with arr bigger in 1 row
}
However, I believe #Gumbo answer explain the concept better then this...
I have the following function. It is expected to insert item into array at position no. When item is inserted, the last element of the array is dropped, i.e. array must always have the same length. Array is taken from string session variable itemstr using split(). The very first element of the array is to be never changed, so I always call this function starting with n===1. The problem is that the function doesn't insert in the sense of splice(). It simply changes the value of element #no
function insert_into_array(no, item)
{
var itemarr = sessionStorage.itemstr.split(',');
if ((no < itemarr.length) && (no > 0)) {
var i;
for (i === itemarr.length - 1; i > no; i--) {
itemarr[i] = itemarr[i - 1];
}
itemarr[no] = item;
sessionStorage.itemstr = itemarr.toString();
}
}
In this line you have a type:
for (i === itemarr.length - 1; i > no; i--) {
It should be actually: i = itemarr.length - 1 and not i === itemarr.length - 1
Not getting what you exactly want.. What i understand is that you need to insert element at position defined by no and remove last element. You can try this in case..
function insert_into_array(no, item)
{
var itemarr = sessionStorage.itemstr.split(',');
if ((no < itemarr.length) && (no > 0)) {
itemarr .splice(no, 0, item); //Insert element at position defined by #no
itemarr .pop(); //removes last element
}
sessionStorage.itemstr = itemarr.toString();
}
Culprit for your function is following line
for (i === itemarr.length - 1; i > no; i--)
here i will be assigned to the value undefined since this is a comparison(===) and not assignment (=). Thus i(undefined) > no will always be false , so no more loop execution.
Simply replace comparison with assignment
for (i = itemarr.length - 1; i > no; i--)
As i understood from the question, you want to insert a variable to an array at a fixed position,and previous content at that position need to shifted and last array value need to be removed.
just use arr.pop() to remove last element and make use of a for loop to shift one position to right.
using jQuery will be more simple here.
I am trying to get all combination of a number. For example, input "123" should return ["123", "231", "213", "312", "321", "132"].
Here is my function:
function swapDigits(input) {
for (var i = 0; i++; i < input.length - 1) {
var output = [];
var inter = input.slice(i, i + 1);
var left = (input.slice(0, i) + input.slice(i + 1, input)).split("");
for (var j = 0; j++; j <= left.length) {
var result = left.splice(j, 0, inter).join("");
output.push(result);
}
}
console.log(output);
return output;
}
However this function returns undefined, could anyone tell me what's going wrong?
The errors with the for loop and scope have already been mentioned. Besides that, the splice method will change the string that it operates on. This means that the inner loop will never terminate because left keeps on growing, so j never reaches left.length.
If you are new to a language, I would suggest starting with an implementation that is close to the algorithm that you want to implement. Then, once you are comfortable with it, use more advanced language constructs.
See this fiddle for an example. This is the algorithm code:
function getPermutations(input)
{
if(input.length <= 1)
{
return [input];
}
var character = input[0];
var returnArray = [];
var subPermutes = getPermutations(input.slice(1));
debugOutput('Returned array: ' + subPermutes);
for(var subPermuteIndex = 0; subPermuteIndex < subPermutes.length; subPermuteIndex++ )
{
var subPermute = subPermutes[subPermuteIndex];
for(var charIndex = 0; charIndex <= subPermute.length; charIndex++)
{
var pre = subPermute.slice( 0, charIndex );
var post = subPermute.slice( charIndex );
returnArray.push(pre+character+post);
debugOutput(pre + '_' + character + '_' + post );
}
}
return returnArray;
}
Basically, this will walk to the end of the string and work its way back constructing all permutations of sub-strings. It is easiest to see this from the debug output for 1234. Note that 'Returned array' refers to the array that was created by the permutations of the sub-string. Also note that the current character is placed in every position in that array. The current character is shown between _ such as the 1 in 432_1_.
Returned array: 4
_3_4
4_3_
Returned array: 34,43
_2_34
3_2_4
34_2_
_2_43
4_2_3
43_2_
Returned array: 234,324,342,243,423,432
_1_234
2_1_34
23_1_4
234_1_
_1_324
3_1_24
32_1_4
324_1_
_1_342
3_1_42
34_1_2
342_1_
_1_243
2_1_43
24_1_3
243_1_
_1_423
4_1_23
42_1_3
423_1_
_1_432
4_1_32
43_1_2
432_1_
This algorithm doesn't enforce uniqueness. So, if you have a string 22 then you will get two results - 22,22. Also, this algorithm uses recursion which I think is quite intuitive in this case, however there are pure iterative implementations if you look for them.
There are several errors in that code.
You have the order of the parts of the for statement incorrect. The order is initialization, test, increment. So for (/* init */ ; /* test */ ; /* increment */)
You're creating a new array for each iteration of your outer loop.
I'm making this a CW because I haven't checked for further errors than the above.
As you can see below, I clearly repeat myself over. I understand that this is bad practice.
So, how can the 4 duplicate lines of code within the if and else statement be refactored into one?
Some guidance toward better practice would be greatly appreciated. Also, any DRY references / tutorials that you found helpful in learning this technique.
$('.inner_wrap .details').click(function() {
var index = $('.inner_wrap .details').index(this);
$('.details').removeClass('here');
$(this).addClass('here');
$('.view').removeClass('active');
$(this).find('.view').addClass('active');
console.log(index);
if(index > 2){
index -= 3;
**// This and its corresponding else statement is the topic of the question**
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');
} else {
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');
}
return false;
});
Note that the code is repeated in both if and else, meaning, it's always executed. Just take it out of the statement:
if (index > 2) {
index -= 3;
}
var elt = $(this).closest('.outer_wrapper').prev('.outer_wrapper');
elt.find('.tabSlide').removeClass('tabShow');
elt.find('.tabSlide:eq(' + index + ')').addClass('tabShow');
Next, note that the jQuery object is just an array. You can simplify your code thus:
if (index > 2) {
index -= 3;
}
var elt = $(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide');
$(elt.removeClass('tabShow')[index]).addClass('tabShow');
Finally, we can eliminate the aux variable, used just to demonstrate how you call the same object:
if (index > 2) {
index -= 3;
}
$($(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow')[index]).addClass('tabShow');
Please, break this into more than one line of code :D
[EDIT]
OK, and just for fun, here's an even more extreme astronaut-type code, getting rid of the remaining if:
$($(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow')[(index <= 2 ? index : index - 3)]).addClass('tabShow');
BUT! It's awfully unreadable and IMO, you should stick with just the first step. Until it becomes a performance issue, don't overdo it. Applying the DRY rule at the cost of readability/maintainability or just sticking everything into a single line of code makes as much sense as reading & writing minified code. Ie, don't do it :).
[EDIT 2]
#StuartNelson reminded me of the existence of the $.eq() function, which would bring the final code to this (broken into several lines):
$(this).closest('.outer_wrapper')
.prev('.outer_wrapper')
.find('.tabSlide')
.removeClass('tabShow')
.eq(index <= 2 ? index : index - 3)
.addClass('tabShow');
You can modify the index only using the if statement and you could keep a variable for the jQuery element used:
$('.inner_wrap .details').click(function() {
var index = $('.inner_wrap .details').index(this);
$('.details').removeClass('here');
$(this).addClass('here');
$('.view').removeClass('active');
$(this).find('.view').addClass('active');
console.log(index);
if(index > 2){
index -= 3;
}
var element = $(this).closest('.outer_wrapper').prev('.outer_wrapper');
element.find('.tabSlide').removeClass('tabShow');
element.find('.tabSlide:eq(' + index + ')').addClass('tabShow');
return false;
});
if(index > 2){ index -= 3; }
**// This and its corresponding else statement is the topic of the question**
$(this).closest('.outer_wrapper').prev('.outer_wrapper')
.find('.tabSlide').removeClass('tabShow')
.eq(index).addClass('tabShow')
Ditch the else, since you're executing that code regardless you don't need to include it in the statement. You can just keep working on the chain, also, since you're first targeting all elements with class tabSlide and then targeting just a specific instance of that class based on its index.
Those two lines are executed last in both the if and else clause, so they can be pulled out of both and put after the entire if/else statement:
if(index > 2){
index -= 3;
}
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');
This rule is always true. If they were the first two lines in both your if and else clause you would pull them out and put them before your if statement instead.
Since all you really care about is setting the index, that is the only thing you need in the if staement, the rest can go out:
if(index > 2){
index -= 3;
}
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');
Is there any way I can prevent javascript from dropping an error if I try to go into a non existing array index?
Example: array[-1] would return error and eventually break all my code. How can I let it just return 'undefined' and let my script go on? I can implement an if statement before checking the array (so that if the index is minor than zero or major than the array size it would skip it) but this would be very tedious!
this is my code:
if (grid[j-1][i])
n++;
if (grid[j+1][i])
n++;
if (grid[j][i+1])
n++;
if (grid[j][i-1])
n++;
if (grid[j-1][i-1])
n++;
if (grid[j+1][i+1])
n++;
if (grid[j-1][i+1])
n++;
if (grid[j+1][i-1])
n++;
It is inside of two loops which both sees J and I starting from zero. I don't want to change them and neither writing another if statement (as you can see, there are already too much of them!). Is there any solution?
Thanks!
If you know the measures of your grid, you can put "sentinel cells" around it.
If you add a -1st index to an array x, it does not count to x.length. Putting an additional last element into the list would increment x.length.
I daresay using sentinel cells combined with the arithmetic counting algorithms mentioned by d_inevitable would be the fastest solution, since it would not involve branches. You even can omit the !! because true will evaluate to 1 and false to 0 in an equalization.
Update:
Do not use index -1. Its an awful lot slower that normal array indexes. See http://jsperf.com/index-1.
You could use ||, which muffles errors, e.g.:
(grid[j-1] || [])[i] || false
(I haven't tested this, but it should work)
Edit: updated based on am not i am's suggestion
A less tedious way while still using ifs would be checking the first index if it's defined:
if (typeof grid[j-1] != "undefined" && grid[j-1][i])
You could create a function to do the checks:
function getArrayValue(arr,key) {
if( key < 0 || key >= arr.length) return null;
return arr[key];
}
But really you should be avoiding out-of-bounds keys anyway.
I would do this:
for(m = Math.max(j-1,0) ; m <= Math.min(j+1,grid.length-1) ; m++)
for (p = Math.max(i-1,0) ; p <= Math.min(i+1, grid[m].length-1) ; p++)
n += !(m == j && p == i) && !!grid[m][p];
How about this for your solution?
for (dj = -1; dj <= 1; ++dj) {
for (di = -1; di <= 1; ++di) {
if ((dj || di) && grid[j+dj] && grid[j+dj][i+di]) {
n++;
}
}
}
If you refactor all those ifs into a single loop like the above, then having to do the extra conditional is not so bad.