Chapter 4 - Exercises

Wow, yes! You are absolutely right. I’ve checked up on this and it is the bitwise NOT operator, but performed x2. The actual calculation that’s performed is complex (not sure if you delved into that), but the result is the same as Math.floor()However, it only rounds down with positive numbers. With negative numbers it rounds up, so is equivalent to Math.ceil().

Thanks for showing me something new! :slightly_smiling_face:

By the way there’s also a more succinct way to write the condition  if (step === undefined);
if (!step)  will do the same thing.

Have a think about the following…

let step;       // this represents our undefined step parameter

console.log(step);                   // => undefined;
console.log(step === undefined);     // => true
console.log(!step);                  // => true

let x = "";     // the value assigned to this variable is an empty string   

console.log(typeof x);               // => "string"
console.log(typeof step);            // => "undefined"
console.log(step === "");            // => false
console.log(step === undefined);     // => true
1 Like

Hi again @Christophe_H,

Here’s my feedback on your solutions for the exercise Reversing an Array.

Part 1 — Creating a new array which is the reverse of the original

Your following line of code…

newArr[i] = arr.length-i;

…will always produce an array of numbers which descend by decrements of -1 from the total number of elements to 1 e.g.

let originalArray = [1, 2, 3, 4, 5];
// => [5, 4, 3, 2, 1]

let originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// => [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

And so, as long as we always input arrays that start with 1 and rise by increments of +1 (whatever their length), this code appears to work. However, as soon as we try to reverse arrays such as the following, your code no longer produces the correct result:

let originalArray = [5, 7, 9, 11];
// => [4, 3, 2, 1]

let originalArray = ['A', 'B', 'C', 'D'];
// => [4, 3, 2, 1 ]

In order to get your code to always produce an array that’s the reverse of the input array, you need to change this line of code to something like the following:

newArr[i] = arr[arr.length-1-i];

Part 2 — Reversing the original array in place

Here you’re doing exactly the same as your Part 1 solution, the only difference being that it’s replacing the original array rather than creating a new one.

However, here, you cannot just make the same amendment as in Part 1, because that would produce the following:

                                                                               //
let inputArray = [1, 2, 3, 4, 5];
// => [5, 4, 3, 4, 5]

let inputArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// => [10, 9, 8, 7, 6, 6, 7, 8, 9, 10]

let inputArray = [5, 7, 9, 11];
// => [11, 9, 9, 11]

let inputArray = ['A', 'B', 'C', 'D'];
// => ['D', 'C', 'C', 'D' ]

Have you already looked at the model solution, and worked out how it achieves the desired result? If not, then, first of all, have a look at the hints (which you can display in the online course book by clicking below the exercise instructions). If you still don’t get it, have a look at other students’ posts here in this topic, with their attempts, solutions, and the help, comments and feedback posted as replies.

Once you’ve finally looked at the model answer and really understood it, another good learning approach 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.

Let us know if you have any questions or need any further guidance.

Keep on learning! :muscle:

what is the difference between passing and binding? Trying to get these definitions straight as words really mean things in computing, not as much leeway as in real life language.

here is a quick web def:

In simple terms… " Passing by value " means that you pass the actual value of the variable into the function. So, in your example, it would pass the value 9. " Passing by reference" means that you pass the variable itself into the function (not just the value )


clear as mud

…seems the thing here is the movement of variable into functions, not just the value of the variable…need to do some examples for meaning as I know this is a fundamental point that must be grasped

Hi CessQ,

Sorry for the delay in providing you with feedback on your solutions to the exercises.

The Sum of a Range

Your solution calculates the sum in most scenarios :ok_hand:
But you haven’t added functionality to handle an undefined step parameter i.e. when the function call omits the step parameter (not when it’s zero) e.g.

range(1, 10);     // needs a default step parameter of 1
range(4, 7);      // needs a default step parameter of 1
range(5, 2);      // needs a default step parameter of -1

Your solution also doesn’t display or log the actual range which is being summed. Instead, it also logs a cumulative total on each iteration. I think both of your  console.log(SumRange)  statements can be removed from the for loops. Then, just one could be placed next to the document.write(SumRange) to log the final sum to the console, although this isn’t actually necessary as document.write(SumRange) already displays this on the web page.

The other problem you have is that the variable SumRange has been declared in global scope. This means that its value won’t be reset if we want to perform multiple calculations with multiple function calls. With each successive function call, the new sum will be added to the previous one, storing a cumulative sum rather than just the sum of the current range being generated. This can easily be fixed by moving the variable declaration to within the function, at the beginning of the function body. Then, in order to display or log the sum of the range generated by each function call, the document.write (and console.log if there is also one) need(s) to moved to within the function at the very end of the function body.

Reversing an Array

Your solution successfully logs a new array which is the reverse of the original :+1:
However, it logs the new array as it’s built up at every iteration of the for loop. This isn’t necessary, and in order to just log the final result, you should move the console.log statement to after the loop, but still within the function.

How did you get on with Part 2 (reversing the original array in place)? Let us know if you have any questions about it.

Keep on learning! :muscle:

1 Like

Hi @Wevlin,

Sorry for the delay in giving you feedback on your  reverseArrayInPlace  solution.

It works perfectly! Great problem solving, and great coding! :muscle:
You clearly don’t need the graphic animations of people on the bus! :smiley:

1 Like

Hi @FrankB,

I’m going to give you my feedback on your fantastic programs separately… so here goes with…

The Sum of a Range

Great modification! It’s always good to be creative with the exercises, and I really like how you’ve used it as an opportunity to also practise and experiment with jQuery, and with HTML input elements and buttons.

That made me chuckle :wink:

Yes that’s correct. By giving your <input> element an attribute of  type="number"  all that does is get the browser to display an input field that is configured to only accept numbers as user inputs. In my browser, I get little up and down arrows which only allow a number (negative or positive) to be selected or entered, but I think it can vary depending on the browser and the version you’re using. Anyway, if we retrieve the number entered — by accessing the Document Object Model (DOM) using jQuery or standard JavaScript — then by default it will be saved to a JavaScript variable as a string i.e. "25" not 25. You can always check this by doing a quick console.log() on the variable name you’ve assigned the input value to. Having pondered this a little, I’m tempted to say that whatever constraints you configure your HTML <input> elements with, then, whatever the user inputs (whether letters, numbers, symbols… etc.) will be characters, and those characters will be saved as string values in JavaScript. I say tempted because I’m actually following this up with a colleague, so I’m holding fire on making such a sweeping statement just yet. But it makes sense to me, especially as HTML is HyperTEXT Markup Language.

Yes, your method works, because by performing an operation with a multiplication operator on a number as a string value (one operand) and a number as a number value type (other operand), JavaScript automatically coerces the string into a number type, and so the expression evaluates to a number type. However, coersion doesn’t always do what you expect, so it’s always best to check.

For example, consider the following:

let x = 6;
let y = "4";

console.log(x * y);   // => 24    (number)
console.log(x - y);   // => 2     (number)
console.log(x / y);   // => 1.5   (number)
// but
console.log(x + y);   // => "64"  (string concatenation)

However, the usual way we ensure we store numbers as number value types in JavaScript is to use either  parseInt()  or  Number()  as follows:

var lowerLimit = parseInt($('#lowerLimitID').val());
var summationStep = Number($('#summationStepID').val());

Perhaps you could now consider how to develop your program further to include the additional functionality that the exercise asks for: setting a default step parameter of 1 when it is left undefined. For your program this would be when the user does not enter a step value. Your program will require a different solution to the one in the model answer. I think it would be interesting for you to see if you can work out why… :thinking:

1 Like

Thank you, Jonathan, as always for your detailed reply. I figured that the type specification—‘number’ versus ‘text’—was only an input control, and I saw Ivan use the ‘parseInt’-function in one of his videos. It’s probably better programming style to use a function like that, but I just happened to notice in trying to sort out the number/test issue that Javascript re-interprets strings to be numbers if the operations applied to them are non-ambiguous (’+’ is ambigupous because it’s used for numbers and strings but ‘*’ is used only for numbers). In any case, thanks again, and I may have to skip your suggestion for further exploration because I have been very busy of late trying to figure out some configuration problems relating to the Ethereum-smart-contract course that I am currently taking and that I really need to move ahead with.

2 Likes

Ok, I had the right thought in my head, but wrote the wrong code :slight_smile:
Now it should work like it’s supposed to:

var start_array = [0,8,6,4,7];
              var new_array = [];

              function reverseArray(array){
                for (var i = 0; i <= array.length-1; i++){
                  new_array.push(array[array.length-1-i]);
                };
                document.write("This is the new array: " + new_array + "<br>");
              };

              document.write("This is the old array: " + start_array + "<br>");
              reverseArray(start_array);

Thank you so much for your support!

I came up with a solution where the code distinguishes, whether start is smaller than end or vice versa. Hope the solution makes sense :smile:

function range(start, end, step){
                var NewArray = [];
                if (start < end){
                  if (step == undefined){
                    for (var i = start; i <= end; i++){
                      NewArray.push(i);
                    };
                  } else if (step < 0){
                    alert("Start is bigger than end, please enter positiv step!");
                  } else {
                    for (var i = start; i <= end; i = i + step){
                      NewArray.push(i);
                    };
                  };
                } else {
                  if (step == undefined){
                    for (var i = start; i >= end; i--){
                      NewArray.push(i);
                    };
                  } else if (step > -1){
                    alert("Start is smaller than end, please enter negativ step!");
                  } else {
                  for (var i = start; i >= end; i = i + step){
                    NewArray.push(i);
                  };
                };
              };
              document.write(NewArray + "<br><br>");
              return NewArray;
            };


            function sum(array){
              var toPrint = 0;
                for (i = 0; i < array.length; i++){
                    toPrint = toPrint + array[i];
                    console.log(array[i]);
                };
              document.write(toPrint + "<br><br>");
            };

            sum(range(5,2));
            sum(range(39,11,-9));

No problem, Frank,

I found this comment very helpful for my own understanding of coersion. I will be bearing it in mind whenever I am considering the logic behind JavaScript coersion. So far, I haven’t been aware of any particular rules, but then again I can’t say that I’ve researched or experimented with it in enough detail to be able to draw any solid conclusions.

Great solutions, @lfsvamaral :+1:

In your The Sum of a Range, your use of the reduce() array method (complete with its callback function) to calculate the sum, is particularly impressive!

A couple of comments:

Are you aware that your solution to Reversing an Array (Part 1 - creating a new array which is the reverse of the original) empties the original array? This is because the array methods pop() and shift() eliminate and return the last and first elements of the array respectively. In contrast, push() and unshift() add elements to the back and front of the array respectively, and do not eliminate the added elements from anywhere else.

As a result of this, after running your code, the new array, which is the reverse of the input array, has been successfully created; but the input array is now an empty array.

You may want to think about how the model answer prevents the original array from being emptied of all its elements.


I know it isn’t very clear, but we don’t actually expect students to do the speed analysis part of this question. But we certainly don’t stop anyone!

I tested this when I originally did this exercise, and to be honest, I didn’t actually find any significant difference in the speed. If anything, my version of the reverseArray function may actually have been slightly faster.

If you’re interested, take a look at this post which summarises my analysis and also quotes from other students’ comments on this.

However, more recently, a student did his own speed test and found that for his solutions the reverseArrayInPlace function was much faster. Have a look at his post if you’re interested.

Keep on learning! … You’re making great progress! :muscle:

Here is my code for the sum of a range:
function range(start, end, step=1){
array1 = new Array();
if (step >0) {
while (start <= end){
array1.push(start);
start +=step;
}
} else if (step < 0) {
while (start >= end) {
array1.push(start);
start += step;
}
} else array1=[];
return array1;
}

function sum(array1){
sum=0;
for (i=0; i<array1.length; i++){
sum += array1[i];
}
return sum;
}

Here is the reverse of the array and reverse inplace:
function reverseArray(arr){
let newArray1 = [];
while (arr.length >0) {
newArray1.push(arr.pop());
}
return newArray1;
}

function reverseArrayInPlace(arr){
let half = Math.floor(arr.length/2);

for (i = 0; i<=half; i++) {
   let temp = arr[i];
   arr[i] = arr[arr.length - 1 -i];
    arr[arr.length - 1 -i] = temp;
}

return arr;
};

Hi @cryptocrom,

Here’s my feedback on your solutions to the Reversing an Array exercise:

Part 1 (creating a new array which is the reverse of the original):ok_hand:

Your solution to Part 2 (reversing the original array in place) works for odd-numbered arrays (although it swaps the middle element with itself, which is unnecessary). However, it doesn’t work for even-numbered arrays: the middle two elements are reversed twice, therefore returning both to their original unreversed positions. To resolve this you need to take another look at your for loop condition
a <= Math.floor(numbers.length / 2);   and work out how to reduce the number of iterations by 1 for both even- and odd-numbered arrays.

If you find you get stuck, or in a muddle, you may want to have a look at this post for some inspiration.

Good luck!

Keep on learning!.. you’re still making great progress! :muscle:

1 Like

Hi again @cryptocrom!

Nice solution for the exercise The Sum of a Range :ok_hand:
It is clear that you have really worked hard to complete this on your own! :muscle:

A few comments…

  • You only need 1 return statement in your range function. It works fine as it is, but you can remove the one at the end of the 1st main if branch. The second one will then capture both main branches of the conditional execution, because it is outside of both branches, but still within the function.

  • It works fine with an if...else if control flow, but you don’t actually need the second condition (a > b) . As the second main branch picks up all of the cases where the if statement condition evaluates to false, you can just make it an else statement.

  • That’s great, and how you should be testing your program to see if it can handle ALL necessary scenarios. This helps to avoid bugs. I would have also added a corresponding…
    console.log(sum(range()));
    // for each
    console.log(range());

… in order to ensure that the sum is also calculated correctly for each different range scenario.

2 Likes

Hi @loksaha1310,

Your solution to the exercise The Sum of a Range successfully handles ascending ranges with any step value (including if it is left undefined) :ok_hand:

However, did you see that the exercise also requires your program to handle descending ranges? You will also need to adjust your default step parameter so that, if the step is left undefined, the function will activate a default step parameter of either 1 or -1, depending on whether it is going to generate an ascending or descending range.

Have a look again at the exercise instructions for more details, and let us know if you have any questions.

1 Like

Great coding @loksaha1310 :muscle:

These are excellent solutions to the exercise Reversing an Array, which show a good grasp of a wide variety of JavaScript syntax :+1:

Your use of a  for...of  loop and the unshift() array method in Part 1 of this exercise, is particularly impressive, as it results in such a clear and concise solution.

I also really like how you’ve called your range function from The Sum of a Range to generate the array to be reversed. This shows that you’re really thinking outside of the box.

Just one other comment…

In the function reverseArrayInPlace , I would declare the variables lengthOfArray, maxIndex and temp with a keyword. Even though your function still executes successfully without doing this, it’s still a good idea to get into the habit of declaring your variables with one of the keywords let , const or var . Then you can gradually start to understand why, and the differences between each of them.

Keep on learning! … You’re making great progress!

2 Likes

The range and sum functions:

<script>


  var array = [];
  function Range(entry, exit){

    for(counter = entry, index = 0; counter <= exit; counter++, index++){
      array[index] = counter;
    }
    return array;
  }

  function ArraySum(array){
    let length = array.length;
    let sum = 0;
    for(counter = 0; counter < length; counter++){
      sum += array[counter];
    }
    return sum;
  }

  function ModRange(entry, exit, step){
    var array = [];
    if(step === undefined){
      for(counter = entry, index = 0; counter <= exit; counter++, index++){
        array[index] = counter;
      }
    return array;
  }

  else if (step < 0){
    for(counter = entry, index = 0; counter >= exit; counter+=step, index++){
      array[index] = counter;
    }
    return array;

  }

  else {
    for(counter = entry, index = 0; counter <= exit; counter+=step, index++){
      array[index] = counter;
    }
    return array;

  }

  }

console.log(Range(1,10));
console.log(ModRange(1,10));
console.log(ModRange(1,10,2));
console.log(ModRange(5,2,-1));

var testArray = [1,2,3,4,5,6,7,8,9,10];

console.log(ArraySum(testArray));

  </script>

Works as supposed to but does not do “wrong order argument check”, which could easily be fixed by “reversing the countdown”.

ReverseArray function:

type or paste code here
```<script>

  function ReverseArray(array){
    newArray = [];
    length = array.length;
    for(counter = 0; counter < length; counter++){
      newArray[counter] = array[length - counter -1];
    }
    return newArray;
  }

var testArray = [1,2,3,4,5,6,7,8,9,10];

console.log(ReverseArray(testArray));

  </script>

Thank you, your feedback is appreciated and completely makes sense.

I originally had this as an an " if (c === undefined) { if (a<b) {…} else {…} } " and then I had an else statement (to the if c === undefined part) with the { if (a<b) {…} else {…} } part nested in that. I had bugs doing it this way and couldn’t seem to nut it out so changed the structure around. When doing it the way I have it, I did have it as an else statement but still had some bugs and so defined this for myself (for readability) more clearly until I solved it all.

Anyways, I have to learn to go over my code at the end and clean things up and shorten statements where possible once I know the program works, that will concrete my understanding I think. Cheers

*Edit…

Also,

I actually tested so many different variations to make sure it worked I just didn’t want to add such a long list of console logs to this. I made sure the console.log(sum(range())); part worked with all variations of numbers (increasing range with default +1 step, decreasing range with default -1 step, increasing range with defined + step and decreasing range with defined - step). Felt like a massive win when I managed to complete this program successfully (even though I know it could be cleaner and tighter).

As soon as I read this I saw 2 possibilities of what it could be - either:

  1.  a <= Math.floor((numbers.length - 1) / 2);
    

or
2. a < Math.floor(numbers.length / 2);

Both seem to work, for the sake of cleaner code I would go with the second one:

a < Math.floor(numbers.length / 2);

Appreciate the feedback, I probably could’ve solved this prior to posting if I had done rigorous testing like I did with the sum of a range exercise.

note: I have now just looked at the link in your post and seen that both options are mentioned with explicit detail of the process and while I decided that the cleaner of the 2 codes was the best option, I only based that decision on user friendliness (readability) now that I have read your post I can see that it is the better option as it does not perform unnecessary computation.
Awesome, glad I could see the issue once you pointed it out and before reading your linked post, I think I am starting to visualise this coding stuff a lot better over the last week or so. It has started to click a little - obviously I still have a long way to go, but I think my brain is now starting to approach these problems differently and I am starting to understand the step by step logic that a computer program requires.
Thanks again, truly appreciate the time, effort and energy you put in.

okay, struggle is real and clearly I will have to repeat this course… hahahaha, which is OK. I had to cheat, yet again for the exercise and look up the code and then go line by line to understand what was created and why. So, I don’t have my own version to make it happen as i kept getting errors, but lo and behold, when i used their code boom it happened. So I won’t post what’s in the solution from the book but will go back to beginning of the JS potion of the course and start again until I get it. Cheers to all who got it on their own.

reverse…

function reverse(array){
var output = [];
for (var i = 0; i <=array.length; i++){
output.push(array.pop());
}
return output;

1 Like