Fix elements and recursion help to understand - javascript

I'm doing a Dynamic Programming excercise about making combination for array n size with result of k numbers combination and stumble upon this solution, I'm trying to understand what end-i+1 >= r-index is doing here can someone explain.
is this to make the current index make combinations with the other remaining index, still how does that work
function combinationUtil(arr,data,start,end,index,r)
{
// Current combination is ready to be printed, print it
if (index == r)
{
for (let j=0; j<r; j++)
{
document.write(data[j]+" ");
}
document.write("<br>")
}
// replace index with all possible elements. The condition
// "end-i+1 >= r-index" makes sure that including one element
// at index will make a combination with remaining elements
// at remaining positions
for (let i=start; i<=end && end-i+1 >= r-index; i++)
{
data[index] = arr[i];
combinationUtil(arr, data, i+1, end, index+1, r);
}
}
// The main function that prints all combinations of size r
// in arr[] of size n. This function mainly uses combinationUtil()
function printCombination(arr,n,r)
{
// A temporary array to store all combination one by one
let data = new Array(r);
// Print all combination using temporary array 'data[]'
combinationUtil(arr, data, 0, n-1, 0, r);
}

Related

Explanation How Rectangle Recursion JavaScript works

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...

recursive function with an array as input

I am trying to create a function that gets chest exercises from an array called chest.
This function needs to be able to pick several exercises at random, which I have done using a random pointer. To stop duplicate exercises I compare the chest exercise picked (i.e chest[pointer]) and compare it against all the values in the final array.
If the new exercise is not already in the final array, the newly picked exercise is returned and then pushed onto the final array. If it is already in the final array, the function is called recursively. The idea being that the function will run recursively until it finds a new exercise which has not already been chosen:
Get Chest:
function getChest(arr){
var pointer = 0;
//random array pointer
pointer = Math.round(Math.random() * (chest.length - 1));
//check for duplicate
for(var i = 0; i < arr.length - 1; i++){
if(arr[i].name === chest[pointer].name){
return getChest(arr);
} else {
return chest[pointer];
}
}
};
The main function uses this method to select exerises randomly. The final array is called 'day'.:
function chooseExercises(){
for(i = 0; i <= 5; i++){
ex = getChest(day);
day.push(ex);
}
}
The problem I am having is that there are still duplicates when I run it. Any idea as to what is going wrong? (I am using angularJS)
Modify your function to this,
function getChest(arr){
var pointer = 0;
//random array pointer
pointer = Math.round(Math.random() * (chest.length - 1));
//check for duplicate
for(var i = 0; i < arr.length; i++){
if(arr[i].name === chest[pointer].name){
return getChest(arr);
}
}
return chest[pointer];
};
Basically, the loop is breaking before the value is checked with its full length.
EDIT: also your loop is running over arr.length-1 times, which actually should be just arr.length.

Skipping multiple elements in a FOR loop, Javascript

I have some file contents I'd like to pass on to my server using a javascript function. In the file, there are many empty lines, or those which contain useless text. So far I read every line in as a string stored in an array.
How do I then loop through that content skipping multiple lines such as lines 24,25, 36, 42, 125 etc. Can I put these element id's into an array and tell my for loop to run on every element except these?
Thanks
you can't tell your for loop to iterate all, but skip certain elements. it will basically just count in any direction (simplified) until a certain critera has been met.
you can however put an if inside your loop to check for certain conditions, and chose to do nothing, if the condition is met. e.g.:
(pseudo code below, beware of typing errors)
for(var line=0; line < fileContents.length; line++) {
if(isUselessLine(line)) {
continue;
}
// process that line
}
the continue keyword basically tells the for loop to "jump over" the rest of the current iteration and continue with the next value.
The isUselessLine function is something you'll have to implement yourself, in a way, that it returns true, if the line with the given linenumber is useless for you.
You can try this its not much elegent but will suerly do the trick
<html>
<body>
<p>A loop which will skip the step where i = 3,4,6,9.</p>
<p id="demo"></p>
<script>
var text = "";
var num = [3,4,6,9];
var i;
for (i = 0; i < 10; i++) {
var a = num.indexOf(i);
if (a>=0) {
continue;
}
text += "The number is " + i + "<br>";
}
document.getElementById("demo").innerHTML = text;
</script>
</body>
You could use something like this
var i = 0, len = array1.length;
for (; i < len; i++) {
if (i == 24 || i == 25) {
array1.splice(i, 1);
}
}
Or you can have an another array variable which got all the items that need to be removed from array1
Another method:
var lines = fileContents.match(/[^\r\n]+/g).filter(function(str,index,arr){
return !(str=="") && uselessLines.indexOf(index+1)<0;
});
If you have many indices to skip, and this depends on the elements of the array, you could write a function that returns the number of elements to skip over for each index in that array (or returns 1, if no skipping required):
for ( let i = 0;
i < array.length;
i += calcNumberOfIndicesToSkip( array, i )){
// do stuff to the elements that aren't
// automatically skipped
}
function calcNumberOfIndicesToSkip( array, i ){
// logic to determine number of elements to skip
// (this may be irregular)
return numberOfElementsToSkip ;
}
In your case:
// skip the next index (i+1)?
for ( let i=0; i<array.length; i+=skipThisIndex(i+1) ){
// do stuff
}
function skipThisIndex(i){
const indicesToSkip = [ 24, 25, 36, 42, 125 ];
return 1 + indicesToSkip.includes(i);
}
// returns 1 if i is not within indicesToSkip
// (there will be no skipping)
// => (equivalent to i++; normal iteration)
// or returns 1 + true (ie: 2) if i is in indicesToSkip
// => (index will be skipped)

Javascript indexing array issue

Hi I have an array that hold the following numbers, however when I loop though the eachNode function(which iterates 13 times) it repeats all the list elements 13 times. I tested everything but it still produces an error, I'm I executing the for loop correctly?
list[61,67,78]
var len = list.length;
fd.graph.eachNode(function (node) { // loops thru all node id's in graph (13)
for (var i = 0; i < len; ++i) {
if (i in list) {
var nody = list[i]; // I put the number in a variable
var nodess = fd.graph.getNode(nody); //this takes the number and matches it with a node id, it "odjectify" it
if (node.id != nodess.id) { // if the list nodes are not the same
node.setData('alpha', 0); //
node.eachAdjacency(function (adj) { // this make the unmatched nodes disappear
adj.setData('alpha', 0, 'end');
});
}
}
}
});
This line is unneeded:
if (i in list)
The in keyword returns true if its right operand contains the property specified by its left operand. When using this with arrays, it returns unexpected results. The behavior of this keyword is insignificant in this context, so you should simply take it out.
Moreover, you need to create the list array like this:
var list = [61, 67, 78];
...however, when I loop though eachNode (which iterates 13 times) it repeats all the list elements 13 times
It doesn't, it in fact iterates over eachNode 13 times. You also made a for loop which will traverse the list array by its length.
Now that you've given me more detail as to what you want, here is the updated code. I hope it works for you:
fd.graph.eachNode(function (node) {
var flag = false;
for (var i = 0; i < len; ++i)
{
var nody = list[i];
var nodess = fd.graph.getNode(nody);
if (node.id == nodess.id) {
flag = true; break;
}
}
if (flag)
{
node.setData('alpha', 0);
node.eachAdjacency(function (adj) {
adj.setData('alpha', 0, 'end');
});
}
});
This is the behavior by design:
You loop over the graph (13 times as you say), then inside each iteration you loop over your array (3 items).
If you only want to loop once over your array, just move it out of the outer loop

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