TypeError: Cannot read properties of undefined (reading 'length'). Codewars task - javascript

I write solutions to tasks and got
TypeError: Cannot read properties of undefined (reading 'length').
This is my solution
function sumArray(array) {
if (array === null || array.length < 2) {
return 0;
}
let sum = 0;
for (let i = 0; i < array.length; i++) {
sum += array[i];
}
return sum - Math.max(...array) - Math.min(...array)
}
Could you help me find an error in my code?

undefined is not === with null. You need to test for both before calling length on your argument, or don't call this method with an undefined argument.

You need to check is array even defined and that it is type array.
And I think you need to return 0 in all variant where argument array is not defined or null
if (!array || (Array.isArray(array) && array.length < 2)) {
return 0;
}

Based on the code you provided, it's possible that the error is being caused by calling the sumArray function with an undefined or null value as its argument. The code below is fixed.
function sumArray(array) {
if (!Array.isArray(array) || array.length < 2) {
return 0;
}
let sum = 0;
for (let i = 0; i < array.length; i++) {
sum += array[i];
}
return sum - Math.max(...array) - Math.min(...array);
}

Related

What is return -1 in javascript?

What is the return -1 on the third to last line of the below code? How does it work and what is its use?
function findElement(arr) {
let right_sum = 0, left_sum = 0;
for (let i = 1; i < arr.length; i++) {
right_sum += arr[i];
for (let i = 0, j = 1; j < arr.length; i++, j++) {
right_sum -= arr[j];
left_sum += arr[i];
if (left_sum === right_sum) {
return arr[i + 1];
}
}
return -1; // what is this?
}
}
It looks like the developer of that piece of code decided to return -1 if the for loop failed to return a value for error checking.
Its common for people to do these kinds of returns as it helps with error handling.
The return operator is used to return a value from inside a function, so the code return -1; makes the findElement function return the value -1 (negative 1) if the for loop doesn't work. This is useful for debugging. If the for loop works, then the function will return arr[i + 1].
It seems to be simulation of native arrays indexOf method. It returns -1 too, if no matches found.

How to fix TypeError: Cannot read property 'length' of undefined in JavaScript?

I am trying to solve a very easy challenge about finding the longest word in a string.
This is the code:
function find(par) {
let arrayWord = par.split(" ");
let longestWord = "";
for (let i = 0; i <= arrayWord.length; i++) {
if (longestWord.length < arrayWord[i].length) {
longestWord = arrayWord[i]
}
}
return longestWord;
}
find("Find the longest word");
I would need help understanding why I am getting this error:
Uncaught TypeError: Cannot read property 'length' of undefined
at find (:5:47)
at :11:1 find # VM959:5 (anonymous) # VM959:11
thank you.
Cannot read property 'length' of undefined comes when it is not able to find variable of certain type(In your case a string) to call the function length. In your case arrayWord[i].length is not a proper string for the last condition of your check as there is no element arrayWord[arrayWord.length] present in the array. That's why arrayWord[i].length is giving you an error for your last iteration. Just change i <= arrayWord.length to i < arrayWord.length
function find(par) {
let arrayWord = par.split(" ");
let longestWord = "";
for (let i = 0; i <arrayWord.length; i++) {
if (longestWord.length < arrayWord[i].length) {
longestWord = arrayWord[i]
}
}
return longestWord;
}
Edits: Changes made as suggested by RobG
Just change condition <= to < and try
function find(par) {
let arrayWord = par.split(" ");
let longestWord = "";
for (let i = 0; i < arrayWord.length; i++) {
if (longestWord.length < arrayWord[i].length) {
longestWord = arrayWord[i]
}
}
return longestWord;
}
console.log(find("Find the longest word"));

Recursive Return Statement

This is a program that I have wrote to solve a problem. Check if there exists a sum of elements that equal to the maximum number in the array, return true if so, false otherwise.
var found = "false";
var max;
function ArrayAdditionI(array) {
max = Math.max.apply(null,array);
var p = array.indexOf(max);
array.splice(p,1);
array.sort(function(a, b){return a-b;});
found = findSum(array, 0, 0);
return found;
}
function findSum(array, sum, startIndex){
for(var i = startIndex; i < array.length ; i++){
sum += array[i];
if(sum === max){
found = "true";
break;
}else if(sum > max){
break;
}
if(i+2 < array.length && sum < max){
findSum(array, sum, i+2);
}
}
if(startIndex < array.length && sum !== max){
return findSum(array, 0, startIndex+1);
}
return found;
}
ArrayAdditionI(readline());
I had to use global variable, found, to indicate where a sum has been found or not. The return statement always returned undefined.
Also, if I use a return statement in the following if statement, the code does not work properly.
if(i+2 < array.length && sum < max){
return findSum(array, sum, i+2);
}
This is not the optimal solution to the problem, but this is the version I got working.
My question is Why am I getting undefined if I use return statement within the if statement. Also, I tried not using global and use return true if sum === max and at the very end return false, it always returns false or undefined.
-- UPDATE 2: Code with error results --
function ArrayAdditionI(array) {
var max = Math.max.apply(null,array);
//remove max element from array
var p = array.indexOf(max);
array.splice(p,1);
//sort array
array.sort(function(a, b){return a-b;});
//call find sum function
return findSum(array, 0, 0, max);
}
function findSum(array, sum, startIndex){
for(var i = startIndex; i < array.length ; i++){
sum += array[i];
if(sum === max){
return true;
}else if(sum > max){
break;
}
if(i+2 < array.length && sum < max){
**return** findSum(array, sum, i+2, max);
}
}
if(startIndex < array.length && sum !== max){
return findSum(array, 0, startIndex+1, max);
}
return false;
}
// calling the first function
ArrayAdditionI([ 7, 2,90, 31, 50 ]);
The start of the program is this call: ArrayAdditionI([ 7, 2,90, 31, 50 ]);
The return should be true.
Also, ArrayAdditionI([ 1,2,3,4 ]); is true.
However, ArrayAdditionI([ 1,2,3,100 ]); is false.
The return statement between ** **, when removed the code works, otherwise I either get false or undefined. I do not understand this part! Why does removing the return solves the problem, I thought every recursive call must be proceeded with a return statement.
Is the problem maybe due to multiple calls ? Am I using recursion in the improper way?
There are a few mistakes on your code that could lead to the error.
T.J. Crowder already said, use actual booleans instead of a string.
The found variable isn't defined inside your findSum function. That makes JavaScript assume you're setting a global variable.
Add var found = false; as the very first line of your findSum function.
Inside the last if inside your for there are a call to the findSum function but it's not returning it's value nor assigning it to the found variable.
Fix those and update your question with the results.
The following function should give you a true or false answer as to whether or not any combination of values inside an array produces the max figure.
var a = [
1, 1, 1, 1, 1, 1,
1, 1, 1, 9
]
var b = [1,1,1,5]
function MembersHoldMaxSum(arr) {
var i, r = false, index, max = Math.max.apply(null, arr), index;
for (i = 0; i <= arr.length - 1; i++) {
for (index = 0; index <= arr.length - 1; index++) {
var new_arr = [], ct;
for (ct = 0; ct <= arr.length - 1; ct++) {
if (index != ct) { new_arr.push(arr[ct]) }
}
while (new_arr.length != 1) {
var sum = 0, ct2 = 0;
for (ct2 = 0; ct2 <= new_arr.length - 1; ct2++) {
sum += new_arr[ct2];
}
if (sum == max) { return true }
new_arr.pop()
}
}
}
return r
}
var returns_true = MembersHoldMaxSum(a);
var returns_false = MembersHoldMaxSum(b);

JavaScript proper way to handle null in JSON object

Here is the code :
for (i = 0; i < data.RecruitingGroups.length; i++) {
data.RecruitingGroups[i].id = i;
if (data.RecruitingGroups[i].Rule.Rules != null) {
for (j = 0; j < data.RecruitingGroups[i].Rule.Rules.length; i++) {
data.RecruitingGroups[i].Rule.Rules[j].id = j;
}
}
}
Problem is that sometimes RecruitingGroups[].Rule is null. So I tried to verify it was not null before continuing and running the next for loop, but it still throws the error:
Uncaught TypeError: Cannot read property 'Rules' of null
How can i bypass this error.
your second loop needs to increment j++ not i++. =)
You're testing if Rule.Rules is null. That's not the problem; Rule itself is null, as evidenced by the error message. You need to test both Rule and Rule.Rules if either can be null.
Try
if (data.RecruitingGroups[i].Rule && data.RecruitingGroups[i].Rule.Rules) {
if (data.RecruitingGroups[i].Rule && data.RecruitingGroups[i].Rule.Rules) {
for (j = 0; j < data.RecruitingGroups[i].Rule.Rules.length; i++) {
data.RecruitingGroups[i].Rule.Rules[j].id = j;
}
}

Get minimum and maximum of object property names that are integers

UPDATED (formulated the problem wrong, see note below)
I have an object that has a set of properties that are named with numbers as shown in the example. The 'numbered names' are not necessarily consecutive, nor do I know where they start or end. I do know that other properties will not be named with numbers.
I know that myObject["propName"] is the same as myObject.propName, but I deliberately write it in the first way because myObject.0 looks weird and doesn't get recognized by all editors.
How do I get the min- and maximum array index?
So in a situation like this
myObject["0"] = undefined
myObject["1"] = {}
myObject["2"] = undefined
myObject["3"] = {}
myObject["4"] = {}
myObject["5"] = undefined
myObject["someOtherProperty"] = {}
would give me this
minIndex(myObject) == 1
maxIndex(myObject) == 4
To all the answers before this edit
Thanks for your replies. I shouldn't have posted this question in a hurry and should have re-read it before committing. It was late and I was in a hurry. My apologies.
By actually seeing my wrong statement (using an array instead of an object) I think that, based on answers for my reformulated problem, I might need to rewrite my code to use an array instead of an object. The reason I'm using an object rather then an array is material for another question.
Efforts so far
I have tried finding a way of converting the property names to an array and then looping through them, but that has proven cludgy. I'm kind of looking for a less error-prone and elegant way.
Edit: Aha! Now the problem becomes more interesting.
Solution 1: Let's solve this in one shot, shall we? For max:
function maxIndex(obj){
var max = -1;
for(var i in myObject){
var val = parseInt(i);
if(isFinite(val)){
if(typeof obj[val] !== 'undefined' && val > max){
max = val;
}
}
}
return max;
}
I think you can convert this to min on your own ;)
Solution 2: Here I'll your object back into what we originally thought it was, in case you really loved one of the other solutions. Then the rest of the answer applies.
function convertObject(obj){
var output = [];
for(var i in myObject){
var val = parseInt(i);
if(isFinite(val)){
output[val] = obj[i]; //Gotta love JS
}
}
return output;
}
Continue as planned!
To find the smallest, begin at the bottom and work your way up until you find it.
function minIndex(myArray){
for(var i = 0; i < myArray.length; i++){
if(typeof myArray[i] !== 'undefined')
return i;
}
}
To get the biggest, start at the top.
function maxIndex(myArray){
for(var i = myArray.length - 1; i >= 0; i--){
if(typeof myArray[i] !== 'undefined')
return i;
}
}
Both are worst case O(n). You can't really do better because the whole array could be empty, and you'd have to check every element to be positive.
Edit: As is mentioned, you can also check if something is not undefined by simply writing if(myArray[i]). Whatever suits your fancy.
var myObject = {};
myObject["0"] = undefined;
myObject["1"] = {};
myObject["2"] = undefined;
myObject["3"] = {};
myObject["4"] = {};
myObject["5"] = undefined;
myObject["someOtherProperty"] = {};
var keys = Object.keys(myObject).map(Number).filter(function(a){
return isFinite(a) && myObject[a];
});
var min = Math.min.apply(Math, keys);
var max = Math.max.apply(Math, keys);
console.log(min, max); //Logs 1 and 4
Documentation and compatibility information for all:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter
Try looping through the array until you find the 1st non-undefined element.
function minIndex(arr){
for(var i = 0, len = arr.length; i < len; i++){
if(arr[i] !== undefined){
return i;
}
}
}
For max index, do the same thing, except in reverse.
function maxIndex(arr){
for(var i = arr.length-1, len = 0; i >= len; i--){
if(arr[i] !== undefined){
return i;
}
}
}
Min:
for(var i = 0; i < myArray.length; i++) {
if(myArray[i] != undefined) {
return i;
}
}
Max:
for(var i = myArray.length-1; i >= 0; i--) {
if(myArray[i] != undefined) {
return i;
}
}
try something like this:
function minIndex(var array){
for(var i = 0; i < array.length; i++)
{
if(typeof array[i] != "undefined")
return i;
}
return null;
}
function maxIndex(var array){
var returnIndex = -1;
for(var i = 0; i < array.length; i++)
{
if(typeof array[i] != "undefined")
returnIndex = i;
}
if(returnIndex !== -1) return returnIndex;
else return null;
}
this takes advantage of the fact that for..in only iterates over defined elements, and uses the index:
function minIndex(arr){ for(el in arr){return el} }
function maxIndex(arr){var v; for(el in arr){v = el}; return v }
CAVEATS:
The second function is not very efficient though, since it loops through the entire array.
This wont work if you are EXPLICITLY setting the undefined indexes.
var max=0;
var min=myArray.length;
for (var i in myArray)
if (myArray[i]!==undefined)
{
max=Math.max(i, max);
min=Math.min(i, min);
}

Categories