Can anyone explain why I am getting this error in Javascript? [Cannot read property 'length' of undefined] - javascript

Here is my code:
function isEven(num) {;
if (num % 2 === 0) {
return true;}
else {
return false;}
}
function convertToIntegers(lst) {
lst.split(' ');
var len = lst.length;
var count = 0;
while (count < len) {
lst[count] = parseInt(lst[count]);
count++}
}
function iqTest(numbers){
var int_list = convertToIntegers(numbers);
var e_list = [];
var o_list = [];
var count = 0;
var len_int = int_list.length;
while (count < len_int) {
if (isEven(int_list[count]) === true) {
e_list.push(count);}
else if (isEven(count) === false) {
o_list.push(count);}
count++}
if (e_list.length < 2 && e_list.length > 0 && o_list.length > 2) {
return e_list[0];}
else if (o_list.length < 2 && o_list.length > 0 && e_list.length > 2) {
return o_list[0];}
}
Everytime I run it I get this error that says "TypeError: Cannot read property 'length' of undefined at iqTest". Can anyone explain to me how I can fix this error. I don't understand why any object would be undefined in my code. Every var declaration I make is complete. I thought undefined only came up if I wrote something like 'var a' without defining it.

Tomer W and Patrick Evans are right. change your helper function
function convertToIntegers(lst) {
lst = lst.split(' ');
var len = lst.length;
var count = 0;
while (count < len) {
lst[count] = parseInt(lst[count]);
count++;
}
return lst;
}
this way you are storing th result of the split and then returning the array when done.
that being said this function isn't needed. Check out the built in array function map

this one is very easy!
in these situations you want to trace the value back.
you use .length in iqTest() in the line var len_int = int_list.length;
the last assignment to int_list is at line var int_list = convertToIntegers(numbers);
glimps at convertToIntegers(numbers) shows no return statement.
therefore conclusion:
convert2Integers() returns nothing into int_list
then you use int_list.length; of undefined
it seems you wish to return lst from convert2Integers()
function convertToIntegers(lst) {
lst = lst.split(' '); // NOTICE CHANGE, + create a different list!
var len = lst.length;
var count = 0;
while (count < len) {
lst[count] = parseInt(lst[count]);
count++
}
return lst; //THIS LINE was Missing!
}

To expand on #Patrick Evans comment you need to save the result of the split then use that for your while loop. Just as a side note you know the number of iterations of the loop so you can use a for loop.
function convertToIntegers(lst) {
//lst.split(' ');
var lst_array = lst.split(' ');
var len = lst_array .length;
var count = 0;
while (count < len) {
lst_array[count] = parseInt(lst_array[count]);
count++}
}
//
//for loop code
//
//for(i=0;i<lst_array.length;i++){
// lst_arry[i] = parseInt(lst_array[i]);
//}

Related

Parameter returns undefined

I am trying to write a function that identifies if a word is an isogram or not. This is what I have done so far:
function isIsogram(word) {
var result;
var counter = 0;
var dubs = 0;
if (word.length === 0) {
result = false;
} else {
var lower = word.toLowerCase();
var array = Array.from(lower);
for (i = 0; i < array.length; i++) {
counter++;
for (j = i + 1; j < array.length; j++) {
if (array[i] === array[j]) {
dubs++;
}
}
}
if ((counter > 0) && (dubs === 0)) {
result = true;
} else if ((counter > 0) && (dubs > 0)) {
result = false;
}
}
console.log(result);
return result;
}
isIsogram("word");
When I run the above code in my browser's javascript console, it works pretty well. But when I post it onto the environment where I am being tested, it gives an error that "word" (the parameter) is undefined.
I even tried hard coding a parameter by declaring a string value for word outside the function, it still said undefined. What am i not doing right?
Seems to work as far as I can see.
Can you provide information about how you call your function isIsogramm('teststring');?
https://jsfiddle.net/TobiObeck/z15eos81/

Missing letters freecodecamp

Actually I found an answer a few minutes ago.
But I found something strange.
This is my answer for 'Missing letters' in freeCodeCamp challenges.
function fearNotLetter(str) {
var string;
for (i=0;i<str.length;i++) {
if(str.charCodeAt(i)+1 < str.charCodeAt(i+1)){
string = String.fromCharCode(str.charCodeAt(i)+1);
}
}
return string;
}
When I change < operator in if statement into != (not same), it doesn't work!
For me, it seems that != works exactly same as < operator does.
(Because 'not same' can mean something is bigger than the other.)
What is the difference between < and != in the code above?
Your code has a small defect that works when you use < but not !=.
If you see str.charCodeAt(i+1); this code is checking one spot past the end of the string on the last iteration and will return a NaN result.
If I provide the string "abce" it will check if f is < NaN. I believe NaN can't be compared to f's value so it doesn't go into the if statement. So it will keep the missing letter d that was found in the previous iterations which is stored in your string variable.
However, if you provide the !=, then with the same scenario it knows f != NaN and goes into the if statement. This then overwrite the actual missing letter and fails your FCC test case because it is replacing the missing d with f in your string variable.
To fix your code, simply change the for loop to end one iteration before the length of the string.
for (i = 0; i != str.length-1; i++) {
}
This is my method without using .charCodeAt() function :)
function fearNotLetter(str) {
var ind;
var final = [];
var alf =['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
str = str.split('');
ind = alf.splice(alf.indexOf(str[0]),alf.indexOf(str[str.length-1]));
for(var i=0;i<ind.length;i++){
if(str.indexOf(ind[i]) == -1){
final.push(ind[i]);
}
}
if(final.length != 0){
return final.join('');
}
return;
}
fearNotLetter("bcef");
My solution:
function fearNoLetter(str){
var j= str.charCodeAt(0);
for(var i=str.charCodeAt(0); i<str.charCodeAt(str.length-1); i++){
j = str.charCodeAt(i - str.charCodeAt(0));
if (i != j){
return String.fromCharCode(i);
}
}
}
My solution:
function fearNotLetter(str) {
let y = 0;
for (let i = str.charCodeAt(0); i < str.charCodeAt(str.length - 1); i++) {
if (str.charCodeAt(y) != i) {
return String.fromCharCode(i);
}
y++;
}
return;
}
console.log(fearNotLetter("ace"));
function fearNotLetter(str) {
let alpha = "abcdefghijklmnopqrstuvwxyz";
let alphabet = []
for(let j = 0; j< alpha.length; j++){
alphabet.push(alpha[j])
}
if (alphabet.length == str.length){
let result = undefined;
return result
}else{
const start =alphabet.indexOf(str[0])
let end = (str.length)-1
const stop = alphabet.indexOf(str[end])
const finish = alphabet.slice(start,stop)
let result = finish.filter(item => !finish.includes(item) || !str.includes(item))
result = String(result)
return result
}
return result
}
console.log(fearNotLetter("abcdefghijklmnopqrstuvwxyz"));

Error while executing mapreduce in mongo-shell

The following error occours
Thu May 23 07:14:53.437 JavaScript execution failed: map reduce failed:{
"errmsg" : "exception: JavaScript execution failed: TypeError: Cannot read property 'product_category' of undefined near '(values[i].product_category)' (line 21)",
"code" : 16722,
"ok" : 0
at src/mongo/shell/collection.js:L970
My map and reduce function are:
map1 = function()
{
emit({Product_id:this.Product_id
},
{
product_category:this.product_category
});
}
reduce1 = function(key, values)
{
var ref = new Array();
var count = 0;
var tmp="";
var pdt_array = new Array();
for (var i = 1; i <= values.length; i++) {
if( i == 1 )
{
pdt_array_array[i] = values[i];
}
else
{
tmp = values[i];
while(i > 1)
{
if(tmp == pdt_array[i])
{
ref.push(values[i].product_category);
count++;
}
i--;
}
pdt_array[i] = tmp;
tmp = "";
}
}
return {product_category:ref, Count:count}
}
db.DummyReverse.mapReduce(map1, reduce1, {out:{reduce:"product_count_while"}})
The issue is that you are not returning the same format from reduce function as you are emitting as value. Since reduce function can be called 0, once or multiple times for each key you must use the exact same format in all of those cases and you cannot assume that your reduce function will be called only once.
Javascript arrays are 0-indexed. So your last for-run want to access a array index, which doesn't exist. I hope I interpret your code right.
[...]
for (var i = 0; i < values.length; i++) {
if ( i == 0) {
pdt_array_array[i] = values[i];
} else {
tmp = values[i];
while(i > 0) {
if(tmp == pdt_array[i]) {
ref.push(values[i].product_category);
count++;
}
i--;
}
pdt_array[i] = tmp;
tmp = "";
}
}
[...]
Take notice at for (var i = 0; i < values.length; i++). So the n-th element has the index n-1. The last element length-1.
Remarks: Are you sure you get no infinite loop with the for-loop increasing i and in the while decreasing it?

Most efficient way to merge two arrays of objects

I've already solved this out. However I'm looking for a faster solution since my variables has thousands of objects.
I have two arrays like this:
var full = [{a:'aa1',b:'bb1'},{a:'aa3',b:'bb2'},{a:'aa3',b:'bb3'},{a:'aa2',b:'bb3'}],
some = [{a:'aa1',b:'bb1'},{a:'aa3',b:'bb3'}];
I'm trying to flag in a new attribute called c in full if the object exist on some. Expected result:
[{a:'aa1',b:'bb1',c:true},{a:'aa3',b:'bb2'},{a:'aa3',b:'bb3',c:true},{a:'aa2',b:'bb3'}]
Some important tips:
some always has less elements than full
both arrays are sorted equal
My current approach is:
var getIndexByAB = function(arr, a,b){
var initialIndex = getIndexByAB.initialIndex || 0,
len = arr.length;
for(initialIndex; initialIndex < len ;initialIndex++ ){
var el = arr[initialIndex];
if( el.b === b && el.a === a ){
getIndexByAB.initialIndex = initialIndex;
return initialIndex;
}
}
return -1;
}
var len = some.length;
for(var i = 0; i < len ; i++){
var el=some[i],
index = getIndexByAB(full,el.a,el.b);
if(index > -1) full[index].c = true;
}
UPDADE: original solution improved using Juan comment.
Since they are sorted, you can just pass an index to start the search from, that will avoid the O(n^2). You were already doing it, but by storing the index in a global variable. Instead, you should pass it as an argument to getIndexByAB.
function getIndexByAB(arr, a,b , initialIndex){
// Was tracking last index by storing it in a global 'this.initialIndex'.
// 'this' points to 'window' in global functions. That's bad, it
// means this function can't be called on different arrays without
// resetting the global
// var initialIndex = this.initialIndex || 0,
initialIndex = initialIndex || 0;
var len = arr.length;
for(initialIndex; initialIndex < len ; initialIndex++ ){
var el = arr[initialIndex];
if( el.b === b && el.a === a ){
// Bad globals
// this.initialIndex = initialIndex;
return initialIndex;
}
}
return -1;
}
var len = some.length;
var lastValidIndex = 0;
for(var i = 0; i < len ; i++){
var el = some[i];
// Pass the index here, so it doesn't start from scratch
var index = getIndexByAB(full, el.a, el.b, lastValidIndex);
if(index > -1) {
full[index].c = true;
lastValidIndex = index;
}
}
By the way, if you do want a function to cache some values, here's how to do it avoiding globals. (Not that you should use it in this case)
var getIndexByAB = (function(){
// This will only be executed once, and is private
// to getIndexByAB (all invocations)
var lastGoodIndex = 0;
return function(arr, a,b, resetIndex){
if (resetIndex) {
lastGoodIndex = 0;
}
var len = arr.length;
for(var index = lastGoodIndex; index < len ; index++ ){
var el = arr[index];
if( el.b === b && el.a === a ){
lastGoodIndex = index;
return index;
}
}
return -1;
};
})();
Alternatively, you could achieve the following by caching it in getIndexByAB.initialIndex but it's not very elegant. The main reason for avoiding this is the fact that getIndexByAB.initialIndex can be modified by anybody else
Since the arrays are both sorted and some is strictly smaller than full, you could save some time by traversing both arrays at the same time with different indexes. As it is, you are traversing full to get the index of the matching element each time, so you have O(N^2) running time, but you only need to continue the search from the last element you matched.
Not as efficient as #Juan's answer (which takes advantage of the sorted nature, among other things), but I thought I'd still present my solution as it incidentally forced me to come up with a solution for cloning and comparing Javacript objects.
Utilities
// Create a copy of x without reference back to x
function clone(x){
return JSON.parse(JSON.stringify(x));
}
// Pass any number of arguments of any type. Returns true if they are all identical.
function areEqual(){
for(var i = 1, l = arguments.length, x = JSON.stringify(arguments[0]); i < arguments.length; ++i){
if(x !== JSON.stringify(arguments[i])){
return false;
}
}
return true;
}
Flagging function
// Your flagLabel being 'c'
function matchAndFlagWith(flagLabel,aFull,aSome){
var aFlagged = clone(aFull);
for(var i1 = 0, l1 = aSome.length, oSome; oSome = aSome[i1], i1 < l1; ++i1){
for(var i2 = 0, l2 = aFlagged.length, oFlagged; oFlagged = aFlagged[i2], i2 < l2; ++i2){
if(areEqual(oFlagged,oSome)){
oFlagged[flagLabel] = true;
}
}
}
return aFlagged;
}
Demo
http://jsfiddle.net/barney/p2qsG/

Creating A Randomised Array with a Single Pre-defined Choice in JavaScript

I'm creating a program that will ask a question and give 5 choices for answers.
One is pre-defined and is correct, the others I want to be random selections from a bank of answers and the entire array is to be shuffled too.
I've written something, but it has some inconsistencies.
For one, sometimes the pre-defined choice appears twice in the list (it appears to skip over my if check).
Another is that sometimes, the editor crashes when I run it.
I use for in loops and I'm worried the crash is caused by a never-ending loop.
Here's my code:
private var numberOfComponents:int;
private var maxComponents:int = 5;
//numberOfComponents returns the length property of my 'components' answer bank
componentsSelection = buildComponentSelectionList(0); //0 is the index of my correct answer
function buildComponentSelectionList(correctItemIndex){
var theArray:Array = new Array();
var indicesOfSelection:Array = getIndicesByIncluding(correctItemIndex);
Debug.Log(indicesOfSelection);
for (var i=0;i<indicesOfSelection.length;i++)
theArray.Push(components[indicesOfSelection[i]]);
return theArray;
}
function getIndicesByIncluding(correctItem){
var indicesArray:Array = new Array();
var numberOfChoices = maxComponents-1;
for(var i=0;i<numberOfChoices;i++){
var number = Mathf.Round(Random.value*(numberOfComponents-1));
addToRandomNumberSelection(indicesArray, number,correctItem);
}
indicesArray.Push(correctItem);
RandomizeArray(indicesArray);
return indicesArray;
}
function addToRandomNumberSelection(indicesArray:Array,number,correctItem){
if(indicesArray.length == 0){
indicesArray.Push(number);
} else {
var doesntExist = true;
for(var i=0;i<indicesArray.length;i++){
if(indicesArray[i] == correctItem)
doesntExist = false;
if (indicesArray[i] == number)
doesntExist = false;
}
if(doesntExist) {
indicesArray.Push(number);
} else {
addToRandomNumberSelection(indicesArray, Mathf.Round(Random.value*(numberOfComponents-1)),correctItem);
}
}
}
function RandomizeArray(arr : Array)
{
for (var i = arr.length - 1; i > 0; i--) {
var r = Random.Range(0,i);
var tmp = arr[i];
arr[i] = arr[r];
arr[r] = tmp;
}
}
The editor is Unity3D, and the code is a version of JavaScript; I think my error is a logic one, rather than a syntactical one.
I feel I've been staring at this code for too long now and I'm missing something obvious.
Can anybody help me?
You can loop through the options and determine the probability that it should be included, then shuffle the included options:
function getRandomOptions(allOptions, correctIndex, count){
var result = [allOptions[correctIndex]];
count--;
var left = allOptions.length;
for (var i = 0; count > 0; i++) {
if (i != correctIndex && Math.floor(Math.random() * left) < count) {
result.push(allOptions[i]);
count--;
}
left--;
}
shuffleArray(result);
return result;
}
function shuffleArray(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var r = Math.floor(Math.random() * i);
var tmp = arr[i];
arr[i] = arr[r];
arr[r] = tmp;
}
}
Demo: http://jsfiddle.net/Guffa/wXsjz/

Categories