0

THE ISSUE

I'm not really a beginner, but this might be a beginner question. I'm trying to increment a count property of an ES6 JavaScript object. The two most successful (as in they give me wrong info, but no error) versions of this minimal code example either return "NaN" or "1" for each fruit's count property. This seems like it should work, but apparently incrementing an numeric object property is not an intuitive concept.

So, here is what I'm trying to do:

Create object of fruits as keys and how many times they appear. End object would look like this:

fruitsObj[fruit].name
fruitsObj[fruit].count

So for "apple":

fruitsObj.apple.name // apple
fruitsObj.apple.count // 4

But, the output I receive is:

{apple: {…}, pear: {…}, banana: {…}, orange: {…}, kumquat: {…}}
apple:{name: "apple", count: NaN}
banana:{name: "banana", count: NaN}
kumquat:{name: "kumquat", count: NaN}
orange:{name: "orange", count: NaN}
pear:{name: "pear", count: NaN}
__proto__: Object

In Version 2 I tried doing existence and type checking, to no avail. I get "1" as the only value for each count:

{apple: {…}, pear: {…}, banana: {…}, orange: {…}, kumquat: {…}}
apple:{name: "apple", count: 1}
banana:{name: "banana", count: 1}
kumquat:{name: "kumquat", count: 1}
orange:{name: "orange", count: 1}
pear:{name: "pear", count: 1}
__proto__: Object

I'm not sure what I'm doing wrong here.

MY CODE

Version 1:

// Declare an array of fruits
var fruitsArr = ['apple', 'pear', 'apple', 'banana', 'orange', 'kumquat', 'orange', 'apple', 'apple', 'orange'];

var fruitsObj = {};

// Loop through each fruit storing name and count.
fruitsArr.forEach(function(fruit, i) {
	
	// Create each named-fruit property in object as a sub-object.
	fruitsObj[fruit] = {};
	
	fruitsObj[fruit].name = fruit;
	
	// FAILS with NaN!
	fruitsObj[fruit].count = ++fruitsObj[fruit].count;
	
});

console.log(fruitsObj);

Version 2:

// Declare an array of fruits
var fruitsArr = ['apple', 'pear', 'apple', 'banana', 'orange', 'kumquat', 'orange', 'apple', 'apple', 'orange'];

var fruitsObj = {};

// Loop through each fruit storing name and count.
fruitsArr.forEach(function(fruit, i) {
	
	// Create each named-fruit property in object as a sub-object.
	fruitsObj[fruit] = {};
	
	fruitsObj[fruit].name = fruit;

	// if fruit count exists and is greater than zero
	if (fruitsObj[fruit].count != undefined && fruitsObj[fruit].count > 0) {
		// increment it
		fruitsObj[fruit].count++;
	} else {
		// set it to one
		fruitsObj[fruit].count = 1;
	}	
	
});

console.log(fruitsObj);

Links I Consulted

I review a bunch of posts and links that sent me down a rabbit hole. Even so, none of them clearly addressed my issue that I could tell.

MY QUESTIONS

  1. Why is my counter not incrementing, but instead returning 'NaN'?
  2. Is there some special way to declare an object property as a number before assigning a value?
  3. What am I missing in my understanding to make this work? How can I increment my object count properties?
4
  • Initially the count property has a value of undefined and undefined + 1 results in NaN. The shortest way to deal with this is simply : fruitsObj[fruit].count = ++(fruitsObj[fruit].count || 0); Commented Mar 6, 2018 at 12:14
  • you cant increment something when there is nothing to increment:fruitsObj = {}. Maybe you should provide us an expected result Commented Mar 6, 2018 at 12:14
  • eeeeeeeeeeeeh you are generating a counter for each fruit and each fruit is inserted once so will always be 1 on the version 2, i don't know if you want a counter or index Commented Mar 6, 2018 at 12:19
  • I really don't understand what you want to "count" exactly. The amount of certain fruit that you have? please be clear with that Commented Mar 6, 2018 at 12:22

3 Answers 3

3

Why is my counter not incrementing, but instead returning 'NaN'?

Because you are trying to increment an undefined property in the first case. In line

fruitsObj[fruit].count = ++fruitsObj[fruit].count;

fruitsObj[fruit].count is undefined, because you never assigned any number value to it. This problem you corrected in second code block.

What am I missing in my understanding to make this work? How can I increment my object count properties?

The problem with second code is this line

// Create each named-fruit property in object as a sub-object.
    fruitsObj[fruit] = {};

You are assigning a new object in every iteration. So even if this fruit is coming the second time, the new object overrides previous value when you assign a new object. You can eliminate this by checking if this object already exist or not like this

// Declare an array of fruits
    var fruitsArr = ['apple', 'pear', 'apple', 'banana', 'orange', 'kumquat', 'orange', 'apple', 'apple', 'orange'];
    
    var fruitsObj = {};
    
    // Loop through each fruit storing name and count.
    fruitsArr.forEach(function(fruit, i) {
    	
    	// Create a fruit object only if it does not exist already.
        if (!fruitsObj[fruit]) {
    	   fruitsObj[fruit] = {};
        }
    	
    	fruitsObj[fruit].name = fruit;
    
    	// if fruit count exists and is greater than zero
    	if (fruitsObj[fruit].count != undefined && fruitsObj[fruit].count > 0) 
        {
    		// increment it
    		fruitsObj[fruit].count++;
    	} else {
    		// set it to one
    		fruitsObj[fruit].count = 1;
    	}	
    	
    });
    
    console.log(fruitsObj);

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, Prakash! Although I think Ori's code is better, cleaner and more efficient, you addressed my specific questions and helped me realize why my code wasn't working, so I'm giving you the win.
3

Initialise the fruit's object with count: 0, when it doesn't exist, and then increment the count by 1 for each fruit with the same name:

// Declare an array of fruits
var fruitsArr = ['apple', 'pear', 'apple', 'banana', 'orange', 'kumquat', 'orange', 'apple', 'apple', 'orange'];

var fruitsObj = {};

// Loop through each fruit storing name and count.
fruitsArr.forEach(function(fruit) {
  // if the object lacks a [fruit] property
  if(!fruitsObj[fruit]) {
    // create a new [fruit] object, with the name and count: 0
    fruitsObj[fruit] = { 
      name: fruit,
      count: 0
    };
  }
	
  // increment the count of the [fruit] object
  fruitsObj[fruit].count++;
});

console.log(fruitsObj);

2 Comments

Thanks! I can see by running the snippet that it works. Can you provide a link to explain why it works?
It's simple - you initialise the object with a count property that is a number (0). Now, all you have to do is increment by one for each appearance of the fruit in the array.
1

In your forEach loop, try only these two lines:

if(fruitObj[fruit]) fruitObj[fruit].count+=1;
else fruitObj[fruit] = {name: fruit, count: 1};

This is instantiating or incrementing, depending on previous instantiation. You cannot increment an uninstatiated value, and in your second version you are instantiating new empty object every time (unconditionally).

1 Comment

Thanks Alexander! I'll have to try this shorter simpler code out. Seems a bit like the singleton design pattern.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.