Chapter 4 - Exercises

I only cut and paste the relevant code, my actual atom file has all the header code, the only reason I included the “body” section was because I’m trying to get user input for the exercise, otherwise I’d only have pasted the “script” section.

So here’s the entire code file:

<html lang="en">
  <head>
    <title>Sum of a Range</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  </head>
  <body>
    <h1>Sum of a Range</h1>
    <input type="text" id="firstNum"> Enter 1st number</input><br><br>
    <input type="text" id="secondNum"> Enter 2nd number</input><br><br>
    <button id="makeArray">submit numbers</button><br><br>
    <script>
      let start = $("#firstNum").val();
      let end = $("#secondNum").val();
      function range(start, end, step = end > start ? 1: -1){
        let numArray = [];
        if (step > 0){
          for (let i = start; i <= end; i += step)
          numArray.push(i);
        } else {
          for (let i = start; i >= end; i += step)
          numArray.push(i);
        };
        return numArray;
      };
      $("#makeArray").click(function(){
        range(start,end)});
    </script>
  </body>
</html>
2 Likes

ok you are not actually passing the values of the input text areas to the range function. the step variable is being assigned -1 but start and end have null values. you need to make sure the onclick event handler

      $("#makeArray").click(function(){
        range(start,end)});

in your click handler also passes the values of input text area 1 and 2 to the range function also.

ps. i haven’t messed with jquery much but perhaps something like this

      $("#makeArray").click(function(){
        range($("#firstnum").val(),$("#secondnum").val())});

that probably wont work because i only spent time on javascritp and not jquery

pps i tried out my suggestion and it does sort of work but passes undefined. perhaps because the input boxes contain string values so you will also need to convert the values in those boxes to numbers. i must look up myself now and get my feet wet with jquery

Thanks for your answer. What confuses me is that the variables are defined as “start” and “end” above and they are defined as:

      let start = $("#firstNum").val();
      let end = $("#secondNum").val();

so wouldn’t that allow me to not have to directly reference those? Also, when I entered that code:

     $("#makeArray").click(function(){
        range($("#firstnum").val(),$("#secondnum").val())});

It’s still throwing an infinite loop… Stumped…

1 Like

you will have to forgive me im not used to reading others code but i see what is happening now. you declared start and end at beginning of the script at page load so they will be assigned null values because nothing is in the text areas yet. if you put the start and end vars inside the range function they are getting the values you are expecting. and browser doesn’t crash then. now it wont let you declare the variables inside the function because they are already declared in the arguments to function so you will need to assign without the let keyword.

okay, this is what I’ve got, still getting a browser crash/infinite loop:

<html lang="en">
  <head>
    <title>Sum of a Range</title>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

  </head>
  <body>
    <h1>Sum of a Range</h1>
    <input type="text" id="firstNum"> Enter 1st number</input><br><br>
    <input type="text" id="secondNum"> Enter 2nd number</input><br><br>
    <button id="makeArray">submit numbers</button><br><br>
    <script>
      function range(start, end, step = end > start ? 1: -1){
        var start = $("#firstNum").val();
        var end = $("#secondNum").val();
        let numArray = [];
        if (step > 0){
          for (let i = start; i <= end; i += step)
          numArray.push(i);
        } else {
          for (let i = start; i >= end; i += step)
          numArray.push(i);
        };
        return numArray;
      };
      $("#makeArray").click(function(){
        range($("#firstNum").val(),$("#secondNum").val())});
    </script>

  </body>

</html>

so the value of var i in your loop is a string value because it came from an input box. you need now to convert that value to a number before you can do math operations. what it is doing at the moment is concatanating var start into a really long string which will never equal var end. var end is also a string so it will also have to be converted into a number. please refer to the parseInt function in jquery or if you prefer and my favourite is the Number() method in javascript to ensure the value you are working with is a number. i woulld use it like this Number(start)

1 Like
/* Here I am after couple of days of studying (not all the time) and learning from you
and meeting with one friend in person about this Ternary 
operator posting my new understanding of it. So I understood everything
and modified a bit this function that in itself if step value is 0 
it will return something... Usually if I would give it a value of 0, my browser
would have crashed when doing it in console :) ...so I just put a bit to return 
something that if we add the step
value of 0 to it. I understand now that this ternary operator in case of step parameter
being undefined will add a value of 1 or - 1 for the loop iterations.*/
      function range(start, end, step = start < end ? 1 : -1) {
  let array = [];
/*  And now I understand that in the loops by saying that i (start) is <= end
or that i >= end we are allowing arrays to go both ways ( + and - ) .. And that we 
actually define by how much in the step parameter. I also noticed that if we
put start to be bigger than end we need to define in our function call
a step negative value (for example)
console.log(range(10,2,-2)) 
--> (5) [10, 8, 6, 4, 2]
Otherwise we will just get an empty array back!
console.log(range(10,2,2))
--> []*/
  if (step === 0) { console.log("0 is not a valid step for this function")

    return false;
                  }

  else if (step > 0) {
    for (let i = start; i <= end; i += step) array.push(i);
  } else {
    for (let i = start; i >= end; i += step) array.push(i);
  }
                  
  return array;
}  


       
1 Like

Hi @pabnan,

That’s absolutely fine if you need to take a look at the solution before being able to complete an exercise on your own. As long as you give it your best shot first. That’s the most important thing — to really spend time wrestling with it yourself first. Then, if you had to get some help, before moving on with the course, make sure you analyse the solution. This is a really important stage in the learning process. You can learn a lot by working out what the solution does and how it does it, and also how to go about “bridging the gap” from what you managed to do (or not) on your own. As long as you understand the code you’re finally posting, that’s job done! :slightly_smiling_face:

Another good learning technique to use is to then try the exercise again from scratch without looking back at the answer (like a memory test). You can also try to do this after having left it for a certain period of time (say, the next day, then after a few days, then a week etc. etc.) This builds up longer-term retention.

By the way, I can’t see your first exercise, The Sum of a Range — are you still working on it? Let us know if you have any questions, or need any pointers.

Keep on learning! :muscle:

Hi @Mucha_Julius,

Feedback for the exercise The Sum of a Range

You’re nearly there!

However, the code you’ve posted doesn’t work when there is no step parameter, because your default step parameter is incomplete. Is this a copy-and-paste error?

Otherwise, it’s looking hopeful! :sweat_smile:

Did you manage to code most of this yourself, before looking at the solution? Really well done if you have — especially the use of the  for...of  loop :muscle:

Hi again, @Mucha_Julius,

Feedback for the exercise Reversing an Array

Good :ok_hand:
Again, it would be nice to know how much you managed to do on your own, or from your own research, before looking at the solutions.

Always format the code you post here in the forum, please. This will avoid errors such as the box you have instead of square brackets (2nd line) and the dash (–) instead of double minus signs (--) for your decrement operator (3rd line).

Hi @LaszloD,

Feedback for exercise The Sum of a Range

This is looking good :ok_hand:
I also like the originality you have brought to the exercise!

However, it took me a while to realise that for your descending ranges:

  • the parameter start still refers to the lowest number (which actually comes at the end of a descending range);
  • the parameter end still refers to the highest number (which actually comes at the start of a descending range).

Is that what you meant to do? If so, I would definitely include some explanatory comments as its confusing for someone trying to understand your code. What also makes it confusing is the fact that, in the exercise instructions in the course book, the example for a function call to produce a descending range is…

range(5, 2, -1);    
// => [5, 4, 3, 2]

…whereas to get your function to generate the same descending range you need to call it with the first 2 parameters in reverse

range(2, 5, -1);   
// => [5, 4, 3, 2]

You could make this more intuitive by changing the parameter names to lowest and highest.

The only scenario that your particular solution cannot handle, is being able to produce a descending range with a default step parameter of -1 (where no step parameter is given). If you haven’t already, take a look at the model answer to see how it handles this.

can someone please explain to me the logic of ReverseArrayInPlace? I’m really struggling with the i <= Math.floor((array.length - 1) / 2); boolean. I don’t get it. If you have an array of length 9 for example then it would read i <= to lowest whole number of (9-1)/2, which results to i <= 4. So once the loop gets half way through, that boolean returns false and we’re out. I understand that as we iterate through, index 0 value becomes the value at index 8, then index 1 becomes value 7, index 2 val 6, index 3 val 5, index 4 val 4, and now we’ve exited the loop because it returns false. So I’ll give my understanding of what the array would look like at that point:

starting array = [1,2,3,4,5,6,7,8,9]
becomes [9,2,3,4,5,6,7,8,9]
becomes [9,8,3,4,5,6,7,8,9]
becomes [9,8,7,4,5,6,7,8,9]
becomes [9,8,7,6,5,6,7,8,9]

And now i = 4 the boolean returns false and we’re out returning an array that looks like: [9,8,7,6,5,6,7,8,9] but we want [9,8,7,6,5,4,3,2,1].

??

What am I missing here?! Someone please explain!

Jonathan

UPDATE-
After further analysis, I think I’m finally understanding this. So each index is “swapping” values with it’s mirrored counterpart. So if you’ve got an array length of 7 for example:
1,2,3,4,5,6,7
becomes 7,2,3,4,5,6,1
becomes 7,6,3,4,5,2,1
becomes 7,6,5,4,3,2,1

and NOW we are cooking with gas!!

1 Like

Hi again, @LaszloD,

Great solutions for Reversing an Array :ok_hand:

Your use of a for...of loop in the first part of the exercise is particularly good, because it makes the function so succinct :+1:

By the way, I’m not sure if you know, but when using arrow functions, if you only have one parameter, you can omit the parentheses, as follows:

const reverseArray = array => {... }

Good work :muscle:

Test Array
function computeRange{(start, end, step = start < end ? 1 : -1)
let arrayNum = [ ];
let count = 0;
for(i = start; i <= end; i++){
arrayNum[count] = i;
count++;
};
return(arrayNum);
};

// Sum of a range //
function arraySum(arrayNum){
let sum = 0;
for(let item of arrayNum){
sum = item + sum;
};
return sum;
};

function computeRange(start,end,step=1){
let arrayNum = [ ];
let count = 0;
if(start < end){
for(i = start; i <= end; i=i+step){
arrayNum[count] = i;
count++;
};
}else{
for(i = start; i >= end; i=i+step){
arrayNum[count] = i;
count++;
};
};
return(arrayNum);
};

Reverse Array

function reverseArray(myArray){
arrayLength = myArray.length;
newArray = [ ];
for(let i=0; i < myArray.length; i++){
newArray[arrayLength-1] = myArray[i];
arrayLength = arrayLength - 1;
};
return newArray;
};

1 Like

@ivan @thecil @jon_m

Just friendly heads up at the end of this section it lists the exercises and link to forum twice. =)

2 Likes

Hi Jon.
Thanks for excellent feedback. I don’t know if you saw it, but the two different for-loops
use the start- and end parameters in the reverse order, and i is more than start:

Descending: for (let i=end; i >= start; i+=step)
Ascending: for (let i=start; i <= end; i+=step)

Anyway, here’s a new version that should take care of all cases. I also added some comments.

/*This function creates an array of numbers from 'start' to 'end'.
It also works with negative numbers and in decending order.
The function also calculates the sum of the numbers and appends
the sum to the last element of the returned array.*/
const myRange = (start, end, step) => {
  let arr = [];

  /*If no 'step' parameter is given, then step defaults to 1 unless
  'start' and 'end' is given in reversed order (i.e. start > end),
in which case the step should be -1 (decending order). Using a ternary operator:*/
 if (!step) {start <= end ? 1 : -1}
  
  //If decending order, 'start' and 'end' are swapped.
  if (start > end) {
    start = [end, end = start][0];
  }
  
  /*Decending order, starts with 'end' and ends with 'start' when
increment (the step) is MORE THAN or equal to 'start'.*/
  if (step < 0) {
    for (let i=end; i >= start; i+=step) {
      arr.push(i);  
    };
  } else {
    //The "normal" case with ascending order.
    for (let i=start; i <= end; i+=step) {
      arr.push(i);
    };
  }

  //Calculating the sum of the elements of the array.
  let sum = 0;
  for (value of arr) {
    sum += value;
  }

  //Pushes the sum into the last element of the array.
  arr.push(sum);

  return arr;
};


returnedArr = myRange(20, -30, -5);
console.log(returnedArr);

//Reversing an array into a new array.
const reverseArray = (array) => {
  let newArray = [];
  for (value of array) {
    newArray.unshift(value);
  }
  return newArray;
};

console.log(reverseArray([1,2,3,4,5]));

//Reversing an array in-place.
const reverseArrayInPlace = (array) => {
  for (let i = 0; i < Math.floor(array.length / 2); i++) {
    let temp = array[i];
    array[i] = array[array.length-1-i];
    array[array.length-1-i] = temp;
  }
  return array;
};

console.log(reverseArrayInPlace([1,2,3,4,5]));
1 Like

Hi, the reverse array part i did all on my own., the reverse array in place i did but got stuck then looked at the solution and tried to understand it.,

On the formatting, I normally copy paste straight from my Atom IDE after I’ve run the program.,

1 Like

Thank you for the final touch ups for my script and all the support during the course, it was very nice to work with you! :))

Cheers and Good luck!

1 Like

var range = function (start,end) {
var arr =[];
if (end > start)
for (let i=start; i< end; i++)

arr.push(i)

else (end< start)
for (let j= start; j>= end; j-- )
arr.push(j)
return arr;

}

var range2 = function (start,end) {
var arr =[];
if (end > start)
for (let i=start; i< end; i=i+step)

arr.push(i);

else (end< start)
for (let j= start; j>= end; j= j+step )
arr.push(j);
return arr;

}

var sum= function(arr){
var sumvar=0;
for (let i = 0; i <arr.length. i++)
sumvar = sum+arr [i];
return sumvar;
}
console.log (sum(range(1,10)))

1 Like

Thanks for your feedback on my range program @jon_m . I fixed the null step variable to return 1 and will post updated script at the bottom of the post.

you are correct about the closing </div> in the function. no need at all for it. I dont know why I had it in my head i document.wrote an opening <div> in my returned text construction. A lapse in thought process.

Regarding the return; statements. I am always unsure whether to return a function or not. I guess now you mention it it is safe to assume return is only needed when returning a value. in that case i also have another few return statements in my code which are not needed but dont seem to break my code.

Also there is another senario i found which failed and that was if start was a negative number and step was a negative but guess its ok because its not part of the exercise.

Regarding CSS. I do have quite a bit of knowledge on CSS1, CSS2 and CSS3. I particularly love the way CSS is heading and it is morphing into a true language of its own now with SASS and SCSS. I should spend more time on it to learn more about the new changes but I use the string prototype methods in my exercises to relearn stuff I used to know and have forgotten in javascript. Its 20 years since I messed around with javascript and much has been forgotten so its good to relearn.

Updated Range script

<!DOCTYPE html>
<html>
  <head>
    <title>Range and Sum Function</title>
  </head>
  <script language="JavaScript">
  function writeToPage(data) {
          // Write some data to page
          if(!data) {
            document.getElementById('myId').innerHTML = "";
          } else {
            document.getElementById('myId').innerHTML += data;
          }
          return;
  }

  function textColor(color) {
    // adds a little color ot the output text
      return "<font color=\"" + color + "\">" + this + "</font>";
  }

  String.prototype.color = textColor; // create new string property for color

  function posToNegative(num) {
    // converts step in range to negative if start > end
    return -Math.abs(num);
  }


  function range(start, end, step) {
    //alert(start + end + step)
    // creates array while start is < end || start > end

    if(!step) {
      step = 1;
    }
    var myArray = new Array();
    if(start > end) {
      // build the array
      step = posToNegative(step); // if start > end  make step negative
       for(let i = start; i >= end; i += step) {
         myArray.push(i);
       }
    } else {
      for(let i = start; i <= end; i += step) {
        myArray.push(i);
      }
    }
    // Make the array text pretty to show to user
    var display = "<h2>Function Range</h2>The numbers ";
    for(let i = 0; i < myArray.length; i++) {
      display += myArray[i].toString().color('green');
      if(i < myArray.length -1) {
        display += ", ";
      }
    }
    writeToPage(display + " were written to " + "myArray".color('red'));
    // write result of range() to the page.
    return(myArray);
  }

  function sum(thisRange) {
    writeToPage("<h2>Function Sum</h2>The numbers ");
    var sum = 0;
    for(let i = 0; i <= thisRange.length -1; i++) {
      sum += thisRange[i];
      writeToPage(Number(thisRange[i]).toString().color('green'))
      if(i < thisRange.length -1) {
        writeToPage(" + ");
      } else {
        writeToPage(" = ");
      }
    }
    writeToPage(Number(sum).toString().color('green'));
    return;
  }


  function getInputValues() {
    // Gets input values from the user and retruns string
    return prompt("I need 3 values to pass to the range().\n These should be a coma separated list of values\n for example\n 1, 10, 2 which convert to start, end, step respectivly");
  }

  function doIt() {
    writeToPage("")
    userRangeValues = getInputValues();
    rangeValuesSplit = userRangeValues.split(",");
    sum(range(Number(rangeValuesSplit[0]), Number(rangeValuesSplit[1]), Number(rangeValuesSplit[2])));
    writeToPage("<br><br><button onClick='doIt()'>Try Another Calculation</button>")

  }
  </script>
  <body id="body" onLoad="doIt()">
    <div id="myId">
    </div>
  </body>
</html>

again thanks for your feedback on my range script.

1 Like