Learn Advanced Array Methods by Building a Statistics Calculator - Step 35

Tell us what’s happening:

I have changed my if else statement to a ternary operator to assign the value of counts[el] with a single assingment operator, cant seem to pass

Your code so far

<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="./styles.css" />
    <script src="./script.js"></script>
    <title>Statistics Calculator</title>
  </head>
  <body>
    <h1>Statistics Calculator</h1>
    <p>Enter a list of comma-separated numbers.</p>
    <form onsubmit="calculate(); return false;">
      <label for="numbers">Numbers:</label>
      <input type="text" name="numbers" id="numbers" />
      <button type="submit">Calculate</button>
    </form>
    <div class="results">
      <p>
        The <dfn>mean</dfn> of a list of numbers is the average, calculated by
        taking the sum of all numbers and dividing that by the count of numbers.
      </p>
      <p class="bold">Mean: <span id="mean"></span></p>
      <p>
        The <dfn>median</dfn> of a list of numbers is the number that appears in
        the middle of the list, when sorted from least to greatest.
      </p>
      <p class="bold">Median: <span id="median"></span></p>
      <p>
        The <dfn>mode</dfn> of a list of numbers is the number that appears most
        often in the list.
      </p>
      <p class="bold">Mode: <span id="mode"></span></p>
      <p>
        The <dfn>range</dfn> of a list of numbers is the difference between the
        largest and smallest numbers in the list.
      </p>
      <p class="bold">Range: <span id="range"></span></p>
      <p>
        The <dfn>variance</dfn> of a list of numbers measures how far the values
        are from the mean, on average.
      </p>
      <p class="bold">Variance: <span id="variance"></span></p>
      <p>
        The <dfn>standard deviation</dfn> of a list of numbers is the square
        root of the variance.
      </p>
      <p class="bold">
        Standard Deviation: <span id="standardDeviation"></span>
      </p>
    </div>
  </body>
</html>
/* file: script.js */
const getMean = (array) => array.reduce((acc, el) => acc + el, 0) / array.length;

const getMedian = (array) => {
  const sorted = array.sort((a, b) => a - b);
  const median =
    array.length % 2 === 0
      ? getMean([sorted[array.length / 2], sorted[array.length / 2 - 1]])
      : sorted[Math.floor(array.length / 2)];
  return median;
}


// User Editable Region

const getMode = (array) => {
  const counts = {};
  array.forEach(el=>counts[el] = counts[el] ? counts[el]+=1 : 1);
  return counts;
}

// User Editable Region


const calculate = () => {
  const value = document.querySelector("#numbers").value;
  const array = value.split(/,\s*/g);
  const numbers = array.map(el => Number(el)).filter(el => !isNaN(el));
  
  const mean = getMean(numbers);
  const median = getMedian(numbers);
  console.log(getMode(numbers));

  document.querySelector("#mean").textContent = mean;
  document.querySelector("#median").textContent = median;
}
/* file: styles.css */
body {
  margin: 0;
  background-color: rgb(27, 27, 50);
  text-align: center;
  color: #fff;
}

button {
  cursor: pointer;
  background-color: rgb(59, 59, 79);
  border: 3px solid white;
  color: white;
}

input {
  background-color: rgb(10, 10, 35);
  color: white;
  border: 1px solid rgb(59, 59, 79);
}

.bold {
  font-weight: bold;
}

Your browser information:

User Agent is: Mozilla/5.0 (X11; Linux x86_64; rv:132.0) Gecko/20100101 Firefox/132.0

Challenge Information:

Learn Advanced Array Methods by Building a Statistics Calculator - Step 35

Okay, so I spent some time working on this and it’s easier than you think. First I’ll format your ternary operator a bit so it’s easier to read.

array.forEach(el => counts[el] = counts[el] ? counts[el] += 1 : 1);

Okay, now, here’s what’s right about your code:

  • The condition is right
  • The logic (reasoning) is right
  • The syntax is (mostly) correct

The problem lies in the if true part of your ternary. Here’s a hint: find the extra equal sign.

If that was too obvious, forgive me. If you need more help, let me know.

Happy coding!

1 Like

I am sorry but i still dont understand what do you mean by double equal, double equal is used for checking the equality but i am supposed to assign it to the increment of the value by 1. which should be +=1 or ++.

you should not have an assignment in the ternary as that would equal two assignments on the same line which is an error. How to sum 1 without assigning?

1 Like

I’m also baffled by this.

Like zidanredha2 said, I’m also confused why you would need a double equal sign. And I tried it and it doesn’t work.

This makes 0 sense to me. sum 1? assignment?

1 Like

the assignment operator is = and it assign the value of what is to the right of the operator to what is on the left of it.
You have a compound assignment in the ternary, which makes two assignments on the same line. JavaScript lets you do that without errors, but you shouldn’t. So, instead of compounding the assigning, you need to make the sum inside the ternary without assignment, as the assignment is already st the beginning of the line.

a question made of only one word is difficult to interpret,
so please expand your questions

Okay, thanks for explaining that part.

okay, I was referencing this line of yours:

What do you mean? Why are we talking about sum 1? What does sum 1 mean and what does it have to do with solving this problem?

I’m confused, adding 1 to count[el] is even part of the original code. If you remove that part you loose the code functionality.
Why does the mention of adding 1 confuses you?

I’ve never before heard someone use the phrase “sum x” in place of “add x”, that’s why I was very confused. So ur just saying I can’t have the equal sign there? Well I’ve tried that, replacing with ++, that doesn’t work either.

1 Like

Don’t use increment operator ++ use only addition operator.

2 Likes

Finally, someone gives me a straight answer, thank you hasan! That allowed me to solve it.
But I still had to brute force try different ways to find it. The proper solution is:

array.forEach(el => counts[el] = counts[el] ? counts[el] + 1 : 1)

But I don’t understand why. For one thing, the el is not in brackets (), when it should because it’s a parameter. Even in the question itself it tells us to use brackets there, I quote

There is another way to write the forEach. Instead of using a block body () => {} for the callback, you can use an expression body :point_right: () =>.

emoji added by me to show where . The second thing I don’t understand is why need counts[el] = counts[el] instead of just counts[el]? The latter worked in previous step (where we did the same task with if and else statements).

Thirdly, why counts[el] + 1 : 1? I don’t understand why you would need += in the code from previous step and + here. And why just 1 for the expression if false? That’s really baffling cause how does the language interpret 1 as counts[el] = 1?

1 Like

Your welcome. For one parameter you can skip parentheses. More than one parameter must be added within the parentheses ().

Example:
the if statement checks if obj[item] exists, and if so, increments it. If it doesn’t exist, it initializes obj[item] to 1. This works well with if-else, but with a ternary operator, you need to specify both the assignment and the conditional check in one expression, hence obj[el] = obj[item] ? obj[item] + 1 : 1;

4 Likes

My deepest apologies - it seems like my explanation is causing some confusion. I totally can see why using the term “double equal sign” can be confused with the == operator, which is not what I meant.

I have edited my post to use the term “extra equal sign”. Please let me know if that makes more sense.

While @hasanzaib1389 and @ILM have done an excellent job explaining, I’ll give my own explanation for no other reason other than that the more explanations there are, the more likely the problem will be understood.

So, what I’ll do is rewrite that ternary in English: (the wrong version)

counts[el] = counts[el] ? counts[el] += 1 : 1

counts[el] =, if counts[el] is true, counts[el] = counts[el] + 1; otherwise = 1

Read it through carefully. Do you see the extra equals sign? Here it is: (Remember that += is only shorthand.)

counts[el] =, if counts[el] is true, counts[el] = counts[el] + 1; otherwise = 1

How can counts[el] = counts[el] = counts[el] = counts[el] + 1? There’s an extra equals sign! it doesn’t make logical sense.

That’s what we need to write it as:

counts[el] =, if counts[el] is true, counts[el] + 1; otherwise = 1

Which is, in code:

counts[el] = counts[el] ? counts[el] + 1 : 1)

And, of course, let’s put that back into the whole arrow function:

array.forEach(el => counts[el] = counts[el] ? counts[el] + 1 : 1)

I hope this makes more sense. It’s tricky to understand, but once you do, it’s surprisingly simple. The idea is all about keeping track of the equal signs, and if you read the lines out loud to yourself, the logical error becomes more obvious.

Once again, I apologize for the confusion I caused!

2 Likes

@nickrg Thanks for writing your reply in good detail. I’ll get back to you later with my own reply, I have to get going now.

1 Like

I have done it just like everyone says and it still says
Your function should still increment the counts variable properly.
here is my code
array.forEach(el => counts[el] = counts[el] ? counts[el] + 1 : 1)

The site is buggy. The code you have is 100% correct. I played with it, and encountered the bug too after adding and deleting spaces in the code.

All you have to do is reset the lesson, delete everything between const counts = {}; and return counts; and paste your code there.

1 Like

Yes, and make sure you avoid commenting. That has messed things up with me sometimes.

Hi @nickrg. Thank you again for this explanation. I now have time for a proper reply. Yes, “extra equal sign” makes much more sense than “double equal sign”. Hopefully by the end of this I can understand the WHY of why this ternary should look like this.

First off, it’s important to look at the previous step, step 34, because step 35 is just re-writing it. The correct answer for step 34 is this, and the part we care about is between the hands.

const getMode = (array) => {
const counts = {};
:point_right:array.forEach(el => {
if (counts[el]){
counts[el]++
} else {
counts[el]=1 :point_left:
}
})
return counts;
}

Now look at the code in the bodies of the if and else statement. We have:
counts[el]++ (which also can be written counts[el]+=1)
and
counts[el]=1

So if we must use addition assignment (for the if) and equals (for the else), why don’t we in the ternary. No one has yet explained this to me.

My first attempt at the code for step 35 looked like this:

array.forEach((el) => counts[el] ? counts[el]++ : counts[el]=1)

And here is the correct one for reference.

array.forEach(el => counts[el] = counts[el] ? counts[el] + 1 : 1)

Now I think I understand the logic of the correct ternary (but I didn’t before). Let me know if I get this right.

The first “counts[el]” that comes after “=>” is NOT part of the condition for the ternary. That’s the key to this (because it looks like it is, and that was holding me up on this problem). So essentially you are transposing counts[el]= in front of what’s writen as the expressioniftrue and the expressioniffalse.

So this is fine and all. But what I’m still confused about is why my original code didn’t work. Can someone please explain this to me? Is it just a fact that ternary’s MUST have a “variable equals” before them?

Because we were never taught this before. All we were taught is this, with this example (I took notes from the lesson it was first indtroduced) I quote:

The ternary operator is a conditional operator and can be used as a one-line if-else statement. The syntax is: condition ? expressionIfTrue : expressionIfFalse.

// if-else statement
if (score > 0) {
  return score
} else {
  return default_score
}

// ternary operator
return score > 0 ? score : default_score
1 Like

Yeah, so the mistake lies in simply copying and pasting the conditions from the original if/else statement we’re converting to a ternary. That’s not how it works, for the reason we discussed earlier: the equal signs logic doesn’t add up.

Now, as to why ++ doesn’t work on the ternary, I think it has to with some very detailed, minute difference between the increment operator, ++, and the + 1 addition. According to MDN:

The increment (++) operator increments (adds one to) its operand and returns the value before the increment, …

Basically, this means the increment operator plays a little game with us here and returns the value before we incremented it, not the value we want. The addition doesn’t have this problem. I recommend you read MDN’s article, Increment (++) - JavaScript | MDN, and pay attention to that first demo. Run the demo and inspect the outputs.

So yeah, it’s a deep detail and the step doesn’t go into all of that. It’s a good point, and maybe this step could be modified a bit.

I’m not a hundred percent sure this is it, but I think so. If anyone else more experienced thinks I’m wrong, please let me know.

Yep!

I think so. Well, I mean, it depends on the situation, but as they’re often used to assign values conditionally to variables, in those cases you must have a “variable equals”, yes.

Hope that clarified…

2 Likes

Thank you, @nickrg, that helps a ton to clarify! Really appreciate you taking the time to teach me. You’re a godsend!

I definitely think this step should be modified. Because how are we supposed to know how to write a ternary properly? As I quoted in my last post, the course didn’t explain any of this when it introduced us to ternaries, or since then.

1 Like