0

So I have a problem for class:

Calculate Sums

Create a function called calculateSums that will accept an array of numbers, and return true if the sum of all the positive numbers is greater than or equal to the sum of the absolute value of all the negative numbers.

Method of completion

  • You should use a while loop in your solution.
  • It does not matter if you consider 0 a positive or negative number because it will not change the sum of either side.
  • After your loop finishes, you should simply return whether the sum of positive numbers is greater than or equal to the sum of negative numbers.
  • It should be possible to call the function as follows:

    calculateSums([-1,2]) returns true

    calculateSums([-1,2,-3]) returns false

In your code, call your function several times and display the arrays used and the result on your HTML page.

I am having trouble figuring out how to use a while loop to do this. I have one, but it's not right. I am also trying to display the result using "document.getElementByID("message").innerHTML..." and I am getting an error I don't understand.

Here is my code:

/**
* This function calculates the absolute sum of an array of numbers
* @inputs a - an array of numbers
* @returns compare - a boolean
*/
        function calculateSum(a) {

            //declare variables and set them equal to 0.
            var result = 0;
            var possum = 0;
            var negsum = 0;
            var compare;
            while (possum >= negsum) {
                for (var i = 0; i < a.length; i++) {
                    var num = a[i];
                    result = result + Math.abs(num);
                    if (num%2 == 0) {
                        possum += result;
                    } else {
                        negsum += result;
                    }
                    result = 0;
                }
                if  (negsum > possum) {
                    compare = false;
                    break;
                } else {
                    compare = true;
                    break;
                }
            }
            if (compare == true) {
                document.getElementById("message").innerHTML = compare;
            } else {
                document.getElementById("message").innerHTML = compare;
            }
        return compare;
        }

Here is my HTML:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Calculate Sums</title>
    <script src = "assignment3.js"></script>
</head>
<body>

    <script>
        calculateSum([-1,2,3,-2]);
        calculateSum([-3,1,-5,2]);
    </script>
    <p id = "message"></p>

</body>
</html> 

I would love someone to help understand the error and offer suggestions of a better way to do this.

Here is the error in the browser:

Uncaught TypeError: Cannot set property 'innerHTML' of null
    at calculateSum (assignment3.js:34)
    at calculateSums.html:12

I am still very new to coding, so I am often times finding myself frustrated. I really appreciate the help I've found on this site.

Update: I figured out how to fix the while statement.

while (possum >= negsum || negsum > possum) 

I'm not sure this is exactly how my teacher imagined it being done because we also have these acceptance criteria:

Calculate Sums

  1. Your code must include a function called calculateSums that accepts an array of numbers and includes a return statement
  2. Your function must include a while loop.
  3. Your code must use Math.abs() to get the absoluate value of any negative numbers.
  4. Your code must NOT include an infinite loop.
  5. Your code must conditionally return true or false.
  6. Your code must include multiple variations of tests to show your function works.
Lisa
  • 211
  • 2
  • 8
  • Your script executes before the `message` element is created in the DOM. Put the script in a separate file and give its HTML tag the `defer` attribute. – CertainPerformance May 04 '18 at 06:56
  • Yup, I thought we were able to put it after in a different program. Thanks! – Lisa May 04 '18 at 06:57
  • The while loop needs to be rewritten and I'm not sure the right way to do it. For the second array I feed in, possum will never get numbers added to it. – Lisa May 04 '18 at 06:58
  • One correction to the code, if should be "if (num >0)" – Lisa May 04 '18 at 07:03
  • 1
    In terms of your approach, I think you can simplify it. There's no need to keep track of negative and positive numbers. Just take the sum of all numbers. If the sum of all numbers `>= 0`, then the positive number sum was larger. You could probably boil it down to a single line: https://jsfiddle.net/4tw0et2s/ – Evan Trimboli May 04 '18 at 07:24
  • 1
    Re-reading the question, I see it has a bunch of arbitrary restrictions, use `Math.abs`, use a while loop etc, so disregard the above as a solution, but maybe something you can look at for fun. – Evan Trimboli May 04 '18 at 07:25

3 Answers3

1

The primary problem in your code is as follows:

When the browser receives the HTML markup in your code, it is processed from top to bottom.

So based on the coed you have shared the code executes in the following order:

The head section loads first as it is on the top. And consequently, your external script assignment3.js also gets loaded. (now the function in the script is available on the global namespace)

<head>
    <meta charset="UTF-8" />
    <title>Calculate Sums</title>
    <script src = "assignment3.js"></script>
</head>

The browser then moves on to the body

<body>

    <script>
        calculateSum([-1,2,3,-2]);
        calculateSum([-3,1,-5,2]);
    </script>
    <p id = "message"></p>

</body>

First, your script tag executes

    <script>
        calculateSum([-1,2,3,-2]);
        calculateSum([-3,1,-5,2]);
    </script>

This works well until this line in the calculateSum function

document.getElementById("message").innerHTML = compare;

Because, at this point, your browser has not gotten around to rendering the <p> tag (the script comes before and executes before this can happen). So document.getElementById("message") can't find the p tag and ends up returning nothing (null). And when you try to access a property on null, you get this error Cannot set property 'innerHTML' of null.

So to fix that, (and as a best practice in general) it's best to put your scripts at the end of the body tag like this (and not in the head):

<body>
    <p id = "message"></p>
    <script src = "assignment3.js"></script>
    <script>
        calculateSum([-1,2,3,-2]);
        calculateSum([-3,1,-5,2]);
    </script>
</body>

This ensures that your page load is not blocked by scripts and also has the side effect that the DOM will have been rendered and ready when your code executes.

Coming to your assignment problem specifically, you can use a while loop to iterate over the array and solve it in a simple manner.

Some change notes:

  1. Move DOM manipulation out of the calculateSum method. This method now has a single clear purpose of calculating the sum and return either true or false.
  2. Write a new function runTestCases which basically creates an array of arrays for the different tests we want to run and runs the calculateSum method for each. It also updates the DOM to reflect the result as stated in your problem statement.
  3. Used while loop to iterate over the array in calculateSum

/**
 * This function calculates the absolute sum of an array of numbers
 * @inputs a - an array of numbers
 * @returns compare - a boolean
 */
function calculateSum(a) {

  //declare variables and set them equal to 0.
  var result = 0;
  var possum = 0;
  var negsum = 0;
  var currentIndex = 0;

  while (currentIndex < a.length) {
    var e = a[currentIndex++];
    if (e < 0) {
      // Negative number
      negsum += Math.abs(e);
    } else {
      // Positive number
      possum += e;
    }
  }

  return possum >= negsum;
}

function runTestCases() {
  // Array of test cases. (You can add or remove tests as needed)
  var tests = [
    [-1, 2],
    [-1, 2, -3]
  ];

  // Get reference of the list element to show the results
  var ul = document.getElementById("result");

  // Iterate over the tests aray and update dom to show each result
  for (var i = 0; i < tests.length; i++) {
    var test = tests[i]; // Get the current test case
    var result = calculateSum(test); // Get the result

    // Create a new DOM element to display the result
    var li = document.createElement('li');
    li.innerHTML = JSON.stringify(test) + " <b> " + result + "</b>";

    //Appenf newly created element to the list
    ul.append(li);

  }
}

runTestCases();
<div>
  <ul id="result"></ul>
</div>
Chirag Ravindra
  • 4,200
  • 1
  • 18
  • 32
  • We have been taught that you put the reference to the js file in the head, but I will move the p tag. – Lisa May 04 '18 at 07:21
  • While that may work in an academic environment when you are learning, it is considered very bad practice in real world apps. You can also just move the `p` tag to the top above the script tag . That should work too. You can place your tag wherever you want as long as you wait for the page to load before doing DOM manipulation. [See this question](https://stackoverflow.com/questions/1033398/how-to-execute-a-function-when-page-has-fully-loaded) and [this other question](https://stackoverflow.com/questions/14028959/why-does-jquery-or-a-dom-method-such-as-getelementbyid-not-find-the-element) – Chirag Ravindra May 04 '18 at 07:39
  • We have not learned JSON yet, so not sure I can use that. Just learned create Element. – Lisa May 04 '18 at 18:48
1

Here is an answer that I think covers all the requirements:

function calculateSums(nums) {
    var posSum = 0,
        negSum = 0,
        i = 0,
        num;

    while (i < nums.length) {
        num = nums[i];

        if (num < 0) {
            negSum += Math.abs(num);
        } else {
            posSum += num;
        }
        ++i;
    }
    return posSum >= negSum;
}
Evan Trimboli
  • 29,097
  • 5
  • 41
  • 64
  • This is great, much simpler. Now I need to display the array and the result in the browser. – Lisa May 04 '18 at 18:29
0

Uncaught TypeError: Cannot set property 'innerHTML' of null at calculateSum (assignment3.js:34) at calculateSums.html:12

You have to call the calculateSum() function after the p tag. It is trying to assign value before it is declare. Put your script before the tag.

n41tik
  • 26
  • 4