Javascript - Use Variable as Array Index - javascript

Trying to use a variable as an array index. Variable addThirteen simply takes i and adds 13 to it. I need to use that result as the array index. Please see my code:
for (var i = 0; i < alphabetArr.length; i ++) {
var addThirteen = (parseInt(i) + parseInt(13));
var newCipher = new cipher(alphabetArr[i].letter, alphabetArr[addThirteen].letter);
}
This results in:
TypeError: undefined is not an object (evaluating
'alphabetArr[addThirteen].letter')
Appreciate any help.

Try printing out the iteration the for loop is on each time:
console.log(i);
console.log(addThirteen);
What seems to be happening here is that when i is alphabetArr.length-13 it is trying to get a character that is outside the array. As it can't do this it throws up the error saying that the letter is undefined, because it is. A solution to this problem is:
for (var i = 0; i < alphabetArr.length - 13; i ++) {

The result you are getting is really depending on what is the alphabetArr variable.
The following is an example where alphabetArr is just an array of strings.
const alphabetArr = "abcdefghejklmnopqrstuvwxyz".split('');
/* If you want to see what alphabetArr really is, uncomment
* the following line an run. (copy snippet to answer to do it)
* The result will be ["a", "b", "c", ..., "z"].
*/
// console.log(alphabetArr);
/* we will always get undefined here because alphabet[i]
* is not an object having the property letter.
* Instead, it is just a string.
*/
for (var i = 0; i < alphabetArr.length; i++) {
console.log(alphabetArr[i].letter);
}
This example gives only undefined because of alphabetArr[i] not being an object whith the property letter but being a string.
Now we will try to see what happens if alphabetArr is an array of objects each having the property letter
const alphabetArr = "abcdefghijklmnopqrstuvwxyz".split('')
.map(letter => ({letter: letter}));
// console.log(alphabetArr);
// result: [ { letter: "a" } , ... , { letter: "z" } ]
/* Here everything works fine until we reach
* the index 13, where the output is m z
*/
for (var i = 0; i < alphabetArr.length; i++) {
// Note that I am not parsing. It's because it is not necessary.
var addThirteen = i + 13;
console.log(alphabetArr[i].letter, alphabetArr[addThirteen].letter);
}
As you see, now we get something, but still, at a certain point, we get the thrown error. This is because the for loop is looping over the entire array.
So when i is 14, addThirteen will be 27. But the length of the array is 26, so alphabetArr[27] is undefined.
Now that we understood the problem, let us solve it.
const alphabetArr = "abcdefghijklmnopqrstuvwxyz".split('')
.map(letter => ({letter: letter}));
for (var i = 0; i < alphabetArr.length - 13; i++) {
// let's skip the addThirteen variable declaration.
console.log(alphabetArr[i].letter, alphabetArr[i + 13].letter);
}
Yes! The solution is to loop over the array minus thirteen, to avoid out of range indexes.
The final code:
const alphabetArr = "abcdefghijklmnopqrstuvwxyz".split('')
.map(letter => ({letter: letter}));
for (var i = 0; i < alphabetArr.length - 13; i++) {
var newCipher = new cipher(alphabetArr[i].letter, alphabetArr[i + 13].letter);
}

Related

Why can I do array[3].toUpperCase(), but array[n].toUpperCase() errors when n=3 (or any num)

I'm trying to solve a coding challenge in this specific way.
The goal is to capitalize every 2nd letter of a string.
When I run the code with letterArray[0] or any other number, the code runs PERFECTLY. but the moment I switch it to letterArray[n], the code crashes. The error message I get says:
Cannot read property 'toUpperCase' of undefined.
Why is letterArray[n].toUpperCase() undefined, when letterArray[n].toUpperCase() is not? understanding the fundamentals is my real concern here.
let theString = "abcdefghijklm" // good
let theStringLength = theString.length // good
let letterArray = theString.split(""); // good
let newArray = []; // good
let i = 0; // good
let n = 1
for (let index = 0; index < theStringLength; index += 2) {
let lowCaseLetter = letterArray[i]
newArray += lowCaseLetter
i += 2
let upCaseLetter = letterArray[n].toUpperCase();
//if i change this to letterArray[0] the code works perfectly
newArray += upCaseLetter
n += 2
}
console.log(newArray)
Your input string has 13 characters. Your loop starts at 0, incrementing by 2 until it hits the limit, so it runs with values 0, 2, 4, 6, 8, 10 and 12. Your n also increments by 2, but starts from 1, so n has the value 1, 3, 5, 7, 9, 11, and 13. Index 13 is past the end of your array, so you read an undefined value, and try to call toUpperCase on it.
You need to fix your code such that you don't effectively require an even length input; as written, your code assumes it can always read one odd index for every even, when that will never be the case for odd length inputs.
One solution is to avoid trying to handle an even and odd in each loop, instead determining whether to uppercase as you go, e.g.:
for (let index = 0; index < theStringLength; ++index) { // Only increment by 1
let val = letterArray[index]; // Read out value
if (index % 2 === 1) val = val.toUpperCase(); // Convert to upper case for odd indices
newArray += val; // Append to result
}
Lets refer to your code, you are running the loop theStringLength time, which denotes the length of the string, that's work as expected. However, as you are incrementing the variable i and n by the same number but with different initial value, that is where the error occurs, the value i stays within the bound as the initial value of i and index are same, if you change initial value of i to be 1 and n to be 0, it should throw same error for i now.
Hopes this explanation helps.
let theString = "abcdefghijklm" // good
let theStringLength = theString.length // good
let letterArray = theString.split(""); // good
let newArray = []; // good
let i = 0; // good
let n = 1
for (let index = 0; index < theStringLength; index += 2) {
let lowCaseLetter = letterArray[i]
newArray += lowCaseLetter
i += 2
let upCaseLetter = letterArray[n].toUpperCase();
//if i change this to letterArray[0] the code works perfectly
newArray += upCaseLetter
n += 2
}
console.log(newArray)

When using strings with numbers at the start in an array key (Indesign 2017, extendscript) they don't get added to the array

Observe:
var groupedLinks = new Array;
for(var i = 0; i < 5; i++) {
linkName = "59notgonnawork" + i;
groupedLinks[linkName] = new Array;
}
I would have expected the result to be the array groupedLinks to be filled up with 5 new keys, the value would be 5 empty arrays.
The actual result in extendscript would be ... grouplinks ... empty.
If I would change this example to be:
var groupedLinks = new Array;
for(var i = 0; i < 5; i++) {
linkName = "notgonnawork" + i;
groupedLinks[linkName] = new Array;
}
It would work perfectly. The only change is the missing "59" at the start of the string used for the array key.
Note that this works perfectly when I run it in console for chrome or firefox. It seems to be indesign and/or extendscript fooling around.
Anything have any ideas why ? I've meanwhile worked around the problem but I'm intrigued.
I would have expected the result to be the array groupedLinks to be filled up with 5 new keys, the value would be 5 empty arrays.
That's exactly what it does, but the way you're viewing the data is likely concealing it because you're not using the proper data structure. Also, property access won't work without using [] because identifiers may not start with a number, so you'd need:
groupedLinks["59notgonnawork0"]
What you're doing isn't meant for arrays, which are expecting sequential numeric indices (though they can technically be assigned other properties too). The type of structure you should be using is a plain object instead.
var groupedLinks = {};
for(var i = 0; i < 5; i++) {
const linkName = "59notgonnawork" + i;
groupedLinks[linkName] = new Array; // Array? plain Object? Depends on its use.
}
Why not trying to push the value in the array on each iteration.
var groupedLinks = new Array;
for(var i = 0; i < 5; i++) {
linkName = "59notgonnawork" + i;
groupedLinks.push(linkName);
}
ExtendScript Arrays are great for stocking data per indeces. If you need key/values objects, why not use… Objects ?
var groupedLinks = {};
for(var i = 0; i < 5; i++) {
linkName = "59notgonnawork" + i;
groupedLinks[linkName] = "Whatever…";
}
alert( groupedLinks["59notgonnawork0" ] ); //"Whatever…"

Pass array values to another array

I have an array of input fields called '$inputFieldsArray' then I slice them to group by 3 into 'newArray' then I need new array value for each item to assign to another array cause in the end I need an array with input fields values grouped by 3. The end goal is to get an array which contains for 9 input fields ex [[i1,i2,i3],[i4,i5,i6],[i7,i8,i9]].
For some reason 'stringArray' output is nothing, first two arrays print correct results. It's probably some mistake I do regarding JS arrays.. Sorry js is not my main language, I try to learn it. Thanks.
Here is a screenshoot with chrome console:
Here is my function:
$($submitButton).click(function () {
// Get number of input fields
let $total = $("input[name^='bodyHeader']").length;
// Get input fields as objects
let $inputFieldsArray = $("input[name^='bodyHeader']");
let newArray = [];
let stringArray = [];
let j = 0;
// Group input fields by 3
for (let i = 0; i < $total - 1; i += 3) {
newArray[j] = $inputFieldsArray.slice(i, i + 3);
j++;
}
// Extract string values from newArray and pass them into stringArray
for (let k = 0; k < newArray.length - 1; k++) {
stringArray[k][0] = newArray[k][0].value;
stringArray[k][1] = newArray[k][1].value;
stringArray[k][2] = newArray[k][2].value;
}
// Print to test results
console.log($inputFieldsArray);
console.log(newArray);
console.log("String Array: " + stringArray);
... // Function logic is not complete
});
SOLUTION:
There is no way to declare dynamic length bidimensional array in js. Use this approach suggested by #Stephan :
stringArray[k] = [newArray[k][0].value, newArray[k][1].value,
newArray[k[2].value];
or this approach suggested by #Lorenzo Gangi:
var matrix = [],
cols = 3;
//init the grid matrix
for ( var i = 0; i < cols; i++ ) {
matrix[i] = [];
}
stringArray[k] is undefined because you defined stringArray as [] (Your browser probably threw an exception). Additionally newArray[k] starts at index 0.
You could write stringArray[k] = [newArray[k][0].value, newArray[k][1].value, newArray[k][2].value] instead.
Basically,
stringArray[k]
is undefined yet, therefore setting its [0] property wont work. May do:
stringArray[k] =newArray[k].map(el=>el.value);
Alltogether:
$($submitButton).click(function () {
let stringArray = $("input[name^='bodyHeader']").toArray().reduce((res,_,i,arr)=>((i%3==0 && res.push(arr.slice(i,i+3).map(e=>e.value))),res),[]);
});

javascript finding biggest number in array not working

i'm filling an array from the input fields and i need to find the biggest number in that array.
Using Math.max(myData) gives me NaN error and when i'm using the "if" statement,sometimes it works and sometimes it doesn't.
Example: if i have 40 and 100 in array ,it gives me 40 as bigger number,but when i have 500 than it works fine.
if i want to make Math.max to work i need to make a new function that converts string into numbers,right?
my code,so you can see where is the mistake.
function Data() {
var h = 0;
var secnd = 1;
var najBr = 0;
for (var i = 0; i < valGrup2; i++)
{
var first = 1;
myDataName[i] = document.getElementById('ime' + secnd).value;
for (var j = 0; j < val2; j++)
{
myData[h] = document.getElementById("inputpolja" + first + secnd).value;
if(myData[h]>najBr){
najBr=myData[h];
}
myDataValue[h] = document.getElementById("inputpolja" + first + secnd).value;
h++;
first++;
}
secnd++;
}
//najBr=Math.max(myData);
console.log(najBr);
Math.max accepts only plain numbers, not an array.
Use this:
function getMaxOfArray(numArray) {
return Math.max.apply(null, numArray);
}
Math.max takes multiple arguments, not an array of the numbers. You can use Function#apply() to have it treat the array as a list of arguments:
Math.max.apply(null /* the context */, myData)

Using search method from string

I'm trying to count the number of times certain words appear in the strings. Every time I run it I get a
uncaught TypeErro: undefined is not a function
I just actually need to count the number of times each "major" appears.
Below is my code:
for(var i = 0; i < sortedarray.length; i++)
{
if(sortedarray.search("Multimedia") === true)
{
multimedia += 1;
}
}
console.log(multimedia);
Here is my csv file which is stored in a 1d array.
"NAME","MAJOR","CLASS STANDING","ENROLLMENT STATUS"
"Smith, John A","Computer Science","Senior","E"
"Johnson, Brenda B","Computer Science","Senior","E"
"Green, Daisy L","Information Technology","Senior","E"
"Wilson, Don A","Information Technology","Junior","W"
"Brown, Jack J","Multimedia","Senior","E"
"Schultz, Doug A","Network Administration","Junior","E"
"Webber, Justin","Business Administration","Senior","E"
"Alexander, Debbie B","Multimedia","Senior","E"
"St. John, Susan G","Information Technology","Junior","D"
"Finklestein, Harold W","Multimedia","Freshman","E"
You need to search inside each string not the array. To only search inside the "Major" column, you can start your loop at index 1 and increment by 4 :
var multimedia = 0;
for(var i = 1; i < sortedarray.length; i += 4)
{
if(sortedarray[i].indexOf("Multimedia") > -1)
{
multimedia += 1;
}
}
console.log(multimedia);
What you're probably trying to do is:
for(var i = 0; i < sortedarray.length; i++)
{
if(sortedarray[i].indexOf("Multimedia") !== -1)
{
multimedia++;
}
}
console.log(multimedia);
I use indexOf since search is a bit of overkill if you're not using regexes.
Also, I replaced the += 1 with ++. It's practically the same.
Here's a more straightforward solution. First you count all the words using reduce, then you can access them with dot notation (or bracket notation if you have a string or dynamic value):
var words = ["NAME","MAJOR","CLASS STANDING","ENROLLMENT STATUS"...]
var count = function(xs) {
return xs.reduce(function(acc, x) {
// If a word already appeared, increment count by one
// otherwise initialize count to one
acc[x] = ++acc[x] || 1
return acc
},{}) // an object to accumulate the results
}
var counted = count(words)
// dot notation
counted.Multimedia //=> 3
// bracket notation
counted['Information Technology'] //=> 3
I don't know exactly that you need this or not. But I think its better to count each word occurrences in single loop like this:
var occurencesOfWords = {};
for(var i = 0; i < sortedarray.length; i++)
{
var noOfOccurences = (occurencesOfWords[sortedarray[i]]==undefined?
1 : ++occurencesOfWords[sortedarray[i]]);
occurencesOfWords[sortedarray[i]] = noOfOccurences;
}
console.log(JSON.stringify(occurencesOfWords));
So you'll get something like this in the end:
{"Multimedia":3,"XYZ":2}
.search is undefined and isn't a function on the array.
But exists on the current string you want to check ! Just select the current string in the array with sortedarray[i].
Fix your code like that:
for(var i = 0; i < sortedarray.length; i++)
{
if(sortedarray[i].search("Multimedia") === true)
{
multimedia += 1;
}
}
console.log(multimedia);

Categories