2

I'm very junior, excuse me if it isn't an appropriate.

Trying to count the objects in an array, ignoring null. This is my code so far:

    function countTheObjects (arr) {

        let count = 0;

          for (let i = 0; i < arr.length; i++) {
             if (typeof arr[i] === 'object') {
               count++;
             }
             if (arr[i] === null) {
               count--;
             }


           }
         return count;
        }

What am I doing wrong?

Edit:

All these codes you guys have given me return exactly the same error mine does. These are the tests the code has to pass:

describe('countTheObjects', function () {
  it('returns the count of objects inside an array of random data types', function () {
    expect(countTheObjects([])).to.equal(0);
    expect(countTheObjects([1, 3, 4, 5])).to.equal(0);
    expect(countTheObjects([1, 3, 4, 5, 'foo'])).to.equal(0);
    expect(countTheObjects([1, 3, 4, 5, {}, {}, {}, 'foo'])).to.equal(3);
    expect(countTheObjects([1, [], 3, 4, 5, {}, {}, {}, 'foo'])).to.equal(3);
    expect(countTheObjects([1, [], null, 3, 4, 5, {}, {}, {}, 'foo'])).to.equal(3);
    expect(countTheObjects([1, {}, [], null, null, 'foo', 3, 4, 5, {}, {}, {}, 'foo'])).to.equal(4);
  });
});
connexo
  • 53,704
  • 14
  • 91
  • 128
VisualXZ
  • 213
  • 3
  • 17
  • Why do you decrease?.. – Ele Mar 22 '18 at 22:57
  • Because it will add one up when finds a null, as is identified as an object? Am I wrong? Thanks for aswering and being so quick. – VisualXZ Mar 22 '18 at 22:59
  • **Add your failing test arrays to the question.** You should have done that from the start. – connexo Mar 22 '18 at 23:11
  • do `console.log(typeof [])`. Your tests are expecting a wrong result. `Arrays` in Javascript are `Objects` – connexo Mar 22 '18 at 23:16
  • 1
    You picked a working, but suboptimal answer. – connexo Mar 22 '18 at 23:22
  • @VisualXZ: Have you tested my answer? – devio Mar 22 '18 at 23:23
  • @VisualXZ Run his tests with your answer. – connexo Mar 22 '18 at 23:24
  • I even added all your tests to my answer. – connexo Mar 22 '18 at 23:29
  • Use a reliable `isObject` type detection method of your choice. Filter the given array by this method. Get the length of the filtered result ... – Peter Seliger Mar 22 '18 at 23:40
  • Marking this Q as duplicate and linking to "why is typeof null 'object'" is not quite right since the OP does not struggle with this matter; but the provided example code shows that the tests exclusively expect direct instances of `Object`. Thus the OP really does look for a reliable type detection method that distinguishes real `Object` instances from all the other instances like e.g. `Array`, `RegExp`, `Date` etc. – Peter Seliger Mar 23 '18 at 00:35

7 Answers7

1

Your code is wrong because typeof null === "object"

function countTheObjects (arr) {
  let count = 0;
  
  arr.forEach(e => {
    if (typeof e === "object" && e !== null) {
      count++;
    }
  });
  
  return count;
}
    
    
alert(countTheObjects([
  1, 2, 3, null, null, 5, 6, null, {}, {}, {}
]));    
Profesor08
  • 1,181
  • 1
  • 13
  • 20
0

Run this:

let arr = []
console.log(typeof arr) // 'object'

Your test expectations are wrong.

Array has typeof 'object' in Javascript.

If you want to make sure arrays are not counted, use Array.isArray(arr). You can also simplify your code considerably using instanceof instead of typeof:

function countTheObjects(arr) {
  let count = 0;
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] instanceof Object && !Array.isArray(arr[i])) {
      count++;
    }
  }
  return count;
}

console.log(countTheObjects([]) === 0);
console.log(countTheObjects([1, 3, 4, 5]) === 0);
console.log(countTheObjects([1, 3, 4, 5, 'foo']) === 0);
console.log(countTheObjects([1, 3, 4, 5, {}, {}, {}, 'foo']) === 3);
console.log(countTheObjects([1, [], 3, 4, 5, {}, {}, {}, 'foo']) === 3);
console.log(countTheObjects([1, [], null, 3, 4, 5, {}, {}, {}, 'foo']) === 3);
console.log(countTheObjects([1, {}, [], null, null, 'foo', 3, 4, 5, {}, {}, {}, 'foo']) === 4);
connexo
  • 53,704
  • 14
  • 91
  • 128
0
  • You don't need to decrease the count when an element is null.
  • Check for !== null && typeof === "object".
  • null is a primitive, however in Javascript typeof null === 'object'.

function countTheObjects(arr) {
  let count = 0;

  for (let i = 0; i < arr.length; i++) {
    if (arr[i] !== null && typeof arr[i] === 'object') {
      count++;
    }
  }
  return count;
}

console.log(countTheObjects([5, null, {}, "", null, {}, ""]));

Using the function reduce from ES6:

function countTheObjects(arr) {
  return arr.reduce((count, obj) => count + (obj !== null && typeof obj === 'object'), 0);
}

console.log(countTheObjects([null, {}, 5, "", null, {}, ""]));
Ele
  • 33,468
  • 7
  • 37
  • 75
0

You could also do something like this

var input = [
  [1, 2, 3], {
    key: 'some value'
  },
  null, null, 5, 6, null, {}
];

console.log(input.reduce((prev, current) => {
  return current !== null ? prev + 1 : prev
}, 0));
Sreekanth
  • 3,110
  • 10
  • 22
0

Here's a simple implementation:

let dataArray = [1, {}, [], null, null, 'foo', 3, 4, 5, {}, {}, {}, 'foo']
let countNotNulls = arr => arr.filter( el => el !== null );
console.log(countNotNulls(dataArray).length);
devio
  • 1,147
  • 5
  • 15
  • 41
0

A reliable approach for answering the OP's question boils down to ... just find or implement the correct/matching type detection method. Then, make use of this method as callback function of the filter method that filters the provided array of different/mixed types. Read the length property of the filtered result.

A generic implementation of an isObject check might look like this ...

function isObject(type) {
  return (!!type && (typeof type === 'object'));
};

... but it will let pass any value/type that neither is null nor undefined nor of any other primitive type. Thus it will also let pass other objects like instances of Array, RegExp, Date etc.

The OP wants to test for direct instances of Object. A solution then might look like the following provided ...

function isObjectObject(type) {
  return (/^\[object\s+Object\]$/).test(Object.prototype.toString.call(type));
}

function getObjectCount(list) {
  return Array.from(list).filter(isObjectObject).length;
}

console.log("(getObjectCount([]) === 0) ? ", (getObjectCount([]) === 0));
console.log("(getObjectCount([1, 3, 4, 5]) === 0) ? ", (getObjectCount([1, 3, 4, 5]) === 0));
console.log("(getObjectCount([1, 3, 4, 5, 'foo']) === 0) ? ", (getObjectCount([1, 3, 4, 5, 'foo']) === 0));
console.log("(getObjectCount([1, 3, 4, 5, {}, {}, {}, 'foo']) === 3) ? ", (getObjectCount([1, 3, 4, 5, {}, {}, {}, 'foo']) === 3));
console.log("(getObjectCount([1, [], 3, 4, 5, {}, {}, {}, 'foo']) === 3) ? ", (getObjectCount([1, [], 3, 4, 5, {}, {}, {}, 'foo']) === 3));
console.log("(getObjectCount([1, [], null, 3, 4, 5, {}, {}, {}, 'foo']) === 3) ? ", (getObjectCount([1, [], null, 3, 4, 5, {}, {}, {}, 'foo']) === 3));
console.log("(getObjectCount([1, {}, [], null, null, 'foo', 3, 4, 5, {}, {}, {}, 'foo']) === 4) ? ", (getObjectCount([1, {}, [], null, null, 'foo', 3, 4, 5, {}, {}, {}, 'foo']) === 4));
.as-console-wrapper { max-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
-2

You are doing unnecessary decrement. You should just move null check to the first if. typeof [] is also 'object'

function countTheObjects (arr) {
let count = 0;

  for (let i = 0; i < arr.length; i++) {
     if (typeof arr[i] === 'object' && arr[i] !== null && !Array.isArray(arr[i]) ) {
       count++;
     }
   }
 return count;
}
Gray Fox
  • 357
  • 3
  • 10
  • Still gives me the same error . 1) countTheObjects returns the count of objects inside an array of random data types: AssertionError: expected 4 to equal 3 + expected - actual -4 +3 at Context. (test/5-objects.test.js:227:69) – VisualXZ Mar 22 '18 at 23:02
  • What is the actual text of the task for these tests? I think there is some deeper issue with it. Maybe counting objects inside nested array or something like that. – Gray Fox Mar 22 '18 at 23:09
  • This function takes an array of different data types. It should return a count of the number of objects in the array. NB, think carefully about how to test if something is an object! Arrays are technically types of objects in JavaScript, as is the value null. However these should not be counted. – VisualXZ Mar 22 '18 at 23:14
  • The issue was that array is also object. I changed code so now it should be correct. – Gray Fox Mar 22 '18 at 23:17
  • All done now. Thank you very very much. I see what you meant there. – VisualXZ Mar 22 '18 at 23:20
  • 1
    `typeof arr[i] === 'object' && arr[i] !== null` can be shortened to `arr[i] instanceof Object`, see my answer. – connexo Mar 22 '18 at 23:25
  • @GrayFox ... what happens if the array contains yet other object types than just instances of `Object` and/or `Array`? – Peter Seliger Mar 23 '18 at 00:47
  • @VisualXZ: This answer doesn't pass in case your array is `var array = [1, {}, [], null, null, 'foo', 3, 4, 5, {}, {}, {}, 'foo']`. It returns `4`. – devio Mar 23 '18 at 00:52
  • It returns 4 and there are 4 objects @Peter Seliger For this particular task the case is correct and verbose. Of course in real case we must check the instance but OP is just learning how to code. – Gray Fox Mar 23 '18 at 01:11