Why does the second array remain empty? - javascript

The goal of this "counter" is to see how many different words are inside the "ToCount"string. To do that it makes ToCount an array and then iterates over the elements, checking if they already are there and if not, adding them there.
The ToCountArr2 remains empty after the loop and a length of 0 is being displayed. Why does that happen and what can I do about it?
I ran a debugger and saw that no elements are added to the second list, as if nothing appenned inside the "if" control if the i-th element of the first array already is inside the second array.
function counter(){
var ToCount = document.getElementById("demo").value; //the contents of a textbox
var ToCountArr1 = ToCount.split(" ");
var ToCountArr2 = new Array;
var i = 0;
var lengthToCountArr1 = ToCountArr1.length;
var wordToPush;
while (i < lengthToCountArr1){
if(ToCountArr2.includes(ToCountArr1[i] === false)) {
wordToPush = ToCountArr1[i];
ToCountArr2.push(wordToPush);
}
i = i + 1;
}
alert(ToCountArr2.length);
}

The issue is with this line if(ToCountArr2.includes(ToCountArr1[i] === false)). Here the braces need to be after ToCountArr1[i], where as this line ToCountArr1[i] === false) is checking whether that value in ToCountArr1 is true or false.
This line
if(ToCountArr2.includes(ToCountArr1[i] === false)) will be evaluated as
if(ToCountArr2.includes(true/false))
depending on result of ToCountArr1[i] === false)
function counter() {
var ToCount = document.getElementById("demo").value; //the contents of a textbox
var ToCountArr1 = ToCount.split(" ");
var ToCountArr2 = new Array;
var i = 0;
var lengthToCountArr1 = ToCountArr1.length;
var wordToPush;
while (i < lengthToCountArr1) {
if (ToCountArr2.includes(ToCountArr1[i]) === false) {
wordToPush = ToCountArr1[i];
ToCountArr2.push(wordToPush);
}
i = i + 1;
}
console.log(ToCountArr2.length);
}
counter()
<input type='text' id='demo' value='Test Values'>
You can minimize if (ToCountArr2.includes(ToCountArr1[i]) === false) { by replacing it with
if (!ToCountArr2.includes(ToCountArr1[i])) {

Your wordcount function should use a parameter so you can pass a string in. This means you can use the wordcount function on an any string, not just the "demo" element. Also, this is a good time to learn about Map -
const wordcount = (str = "") =>
{ const result =
new Map
for (const s of str.split(/ /))
if (s === "")
continue
else if (result.has(s))
result.set(s, result.get(s) + 1)
else
result.set(s, 1)
return Array.from(result.entries())
}
const prettyPrint = (value) =>
console.log(JSON.stringify(value))
<!-- pass this.value as the string for wordcount
-- wordcount returns a value that we could use elsewhere
-- prettyPrint displays the value to the console
-->
<input onkeyup="prettyPrint(wordcount(this.value))">
Run the code snippet and copy/paste the following line into the field -
this is the captain speaking. is this the commander?
You will see this output -
[["this",2],["is",2],["the",2],["captain",1],["speaking.",1],["commander?",1]]

Here is an working example. I think it will help you right way. Here I use indexOf to check the value exist on a array.
function counter(){
var ToCount = "I am string just for text.";//document.getElementById("demo").value; //the contents of a textbox
var ToCountArr1 = ToCount.split(" ");
var ToCountArr2 = new Array;
var i = 0;
var lengthToCountArr1 = ToCountArr1.length;
var wordToPush;
while (i < lengthToCountArr1){
if( ToCountArr2.indexOf(ToCountArr1[i]) == -1 ) {
wordToPush = ToCountArr1[i];
ToCountArr2.push(wordToPush);
}
i = i + 1;
}
alert(ToCountArr2.length);
}
counter();

Related

getting undefined from a function

Hello Write a function to convert a name into initials. This kata strictly takes two words with one space in between them.
this is my code.
function abbrevName(name) {
var first;
var last;
var new1 = name.split("")
for (var i = 0; i < new1.length; i++) {
if (new1[i] == new1.toUpperCase) {
first = new1[i]
if (new1[i] == new1.toUppercase && first == defined) {
last = new1[i]
}
return first + "." + last;
}
}
/enter code here
}
abbrevName("Faris Abutaya")
i am getting undefined help me please
You're getting undefined from your function because you need to return something from it.
Try adding a return statement near the bottom and you'll get an output. What you actually need to return I'll leave up to you.
function abbrevName(name) {
var first;
var last;
var new1 = name.split('');
for (var i = 0; i < new1.length; i++) {
if (new1[i] == new1.toUpperCase) {
first = new1[i];
if (new1[i] == new1.toUppercase && first == defined) {
last = new1[i];
}
return first + '.' + last;
}
}
return new1;
}
abbrevName('Faris Abutaya');
Some problems with your code are noted in comments here:
function abbrevName(name) {
var first;
var last;
var new1 = name.split("")
for (var i = 0; i < new1.length; i++) {
if (new1[i] == new1.toUpperCase) {
first = new1[i]
// toUpperCase needs `()` to be called; new1 holds the array, not a letter; `== defined` is invalid
if (new1[i] == new1.toUppercase && first == defined) {
last = new1[i] // this statement will run as soon as first is found (so last = 'F')
}
return first + "." + last; // return happens as soon as first `if` condition is true
}
}
}
abbrevName("Faris Abutaya")
Here is revised code. Note that console.log statements help to debug because we can see what each variable holds at various points in the script. (To see your browser console, use f12 or ctrl+shift+i)
function abbrevName(name) {
const letters = name.split(""); // Renamed new1 to letters
let first ="", last = "";
let firstFound = false, lastFound = false; // New variables
console.log(letters);
for (let i = 0; i < letters.length; i++) {
console.log(letters[i]);
if(letters[i] == letters[i].toUpperCase()){ //Compare letter to letter, not letter to array
if(firstFound == false){
firstFound = true; // Now we have a way to know last is coming
first = letters[i];
console.log("first: " + first);
}
else{ // firstFound is not false
lastFound = true
last = letters[i];
console.log("last: " + last);
}
}
}
return first + "." + last; // return statement moved out of for loop
}
console.log(abbrevName("Faris Abutaya"));
There are many mistake in the written code.
toUppercase is a function and it should be called as a method of the string. Therefore the code inside the first if statement would never run. For example:
console.log( "h".toUppercase );
//H
new1 is an array of characters and you should call toUpperCase for each character not the whole array.
3.You should also check whether first is defined or not.
function abbrevName(name) {
var first;
var last;
var new1 = name.split("");
for (var i = 0; i < new1.length; i++) {
if (new1[i] === new1[i].toUpperCase() && new1[i] != " ") {
if(first == undefined){
first = new1[i];
}else if (new1[i] == new1[i].toUpperCase() && first != undefined){
last = new1[i];
return first + "." + last ;
}
}
}
}
abbrevName("Faris Abutaya")
//F.A
-It would be so much nicer to do it with RegEx. Because the code you wrote will just work in the times which user enters some names containing just 2 words and capitalizes first letters.

Any alternative way of using this .length & .split()?

I want to split lower, upper & also the value of textBox without using .split() and also I want
to find the length of the string without using .length. Can anybody solve my problem I am tried but
I cannot find the exact logic for this problem.
var lowercase = "abcdefghijklmnopqrstuvwxyz";
var uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
function Print() {
var input = document.getElementById('demo').value;
document.write(document.getElementById('demo1').innerHTML = toUpper(input));
}
function toUpper(input) {
var upperCase = uppercase.split(""); //other way to split uppercase
var lowerCase = lowercase.split(""); //other way to split lowercase
var inputText = input.split(""); //other way to split input
var newText = "";
var found;
for (var i = 0; i < inputText.length; i++) { //not using .length to other way to find the size of inputText
found = false;
for (var ctr = 0; ctr < lowerCase.length; ctr++) { //not using .length other way to find the size of lowerCase
if (inputText[i] == lowerCase[ctr]) {
found = true;
break;
}
}
if (found) { //true
newText = newText + upperCase[ctr];
} else {
newText = newText + inputText[i];
}
}
return newText;
}
You can count the length of a string using the array function reduce.
Reduce loops over all elements in an array and executes a function you give it to reduce it to one value, you can read more here.
To get reduce working on strings, you need to use Array.from, like this:
Array.from(lowerCase).reduce((sum, carry) => sum + 1, 0) // 26
Reduce accepts a starting argument, which we set to zero here.
This way you do not need to use the split or length functions.
You don't need to check if the input is in a string either, you can use charCodeAt() and fromCharCode().
If you take your input and loop through it using Array.from() then forEach, you can get something which looks like this:
function print() {
const input = document.querySelector('#input').value;
document.querySelector('#target').value = stringToUpper(input);
}
function stringToUpper(input) {
let output = "";
Array.from(input).forEach(char => output += charToUpper(char));
return output;
}
function charToUpper(char) {
let code = char.charCodeAt(0);
code >= 97 && code <= 122 ? code -= 32 : code;
return String.fromCharCode(code);
}
<div>
<input id="input" placeholder="enter text here">
</div>
<button onclick="print()">To Upper</button>
<div>
<input id="target">
</div>
The key line is where we take the output and add the char (as upper) to it:
output += charToUpper(char)
If you don't know about arrow functions, you can read more here
This line:
code >= 97 && code <= 122 ? code -= 32 : code;
is just checking if the char is lower case (number between 97 and 122) and if so, subtracting 32 to get it to upper case.
The reason it is subtract not add is in utf-16, the chars are laid out like this:
ABCDEFGHIJKLMNOPQRTUWXYZabcdefghijklmnopqrtuwxyz
See here for more
I don't know what you mean by "split the value of textBox", but one way to determine the length of a string without using .length would be to use a for...of loop and have a counter increment each time it runs to keep track of the number of characters in the string.
let string = 'boo'
let lengthCounter = 0
for (let char of string) {
lengthCounter++
}
//lengthCounter = 3
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
You can define your own split and length functions:
function mySplit(a){
var counter = 0;
rslt = [];
var val = a[counter];
while(typeof val != "undefined"){
rslt.push(a[counter]);
counter ++;
val = a[counter];
}
return rslt;
}
function myLength(a){
var counter = 0;
var val = a[counter];
while(typeof val != "undefined"){
counter ++;
val = a[counter];
}
return counter;
}
Your function now should be like:
function toUpper(input) {
var upperCase = mySplit(uppercase);
var lowerCase = mySplit(lowercase);
var inputText = mySplit(input);
var newText = "";
var found;
for (var i = 0; i < myLength(inputText); i++) {
found = false;
for (var ctr = 0; ctr < myLength(lowerCase); ctr++) {
if (inputText[i] == lowerCase[ctr]) {
found = true;
break;
}
}
if (found) { //true
newText = newText + upperCase[ctr];
} else {
newText = newText + inputText[i];
}
}
return newText;
}
The simplest way would be to just use the build in function of javascript .toUpperCase() (see example 1). https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase
Else if you insist on using a for.loop you may do so aswell (see example two). You do not need the split() function since a string already is an arrayof characters. Also be aware that not all characters in the web have lowercase counterparts, so the logic itself is flawed.
//REM: This lines are not required.
/*
var lowercase = "abcdefghijklmnopqrstuvwxyz";
var uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
function Print() {
var input = document.getElementById('demo').value;
document.write(document.getElementById('demo1').innerHTML = toUpper(input));
}
*/
//REM: Version 1 (using string.toUpperCase())
(function toUpper1(input){
var tReturn = (input || '').toUpperCase();
console.log('toUpper1', tReturn);
return tReturn
}('abcDEFghiJKL'));
//REM: Version 2 (using your way)
(function toUpper2(input){
var tReturn = '';
if(input && input.length){
for(let i=0, j=input.length; i<j; i++){
tReturn += (input[i] === input[i].toLowerCase()) ? input[i].toUpperCase() : input[i]
}
};
console.log('toUpper2', tReturn);
return tReturn
}('abcDEFghiJKL'));

Arguments getting re-assigned

I am trying to strip out the display name from an email, e.g.
Steve<steve#steve.com> to steve#steve.com
function test1() {
var testemail = ["Steve<steve#steve.com>","displayname<display#steve.com>"];
var debug = stripEmail(testemail);
var debug9 = "";
}
function stripEmail(email) {
//Give me an email with a display name and I will strip out the display name
//"<Steve Gon> stevegon#google.com"
if (typeof email === 'string') {
var arr = [email];
} else {
var arr = email;
}
for (i=0; i<arr.length; i++) {
if (arr[i].search("<")>-1) {//If there is no less than, then it doesn't have a display name
var part1 = arr[i].split("<");
if (part1.length == 2) {
arr[i] = part1[1].replace(">","");
arr[i] = arr[i].replace("<","");
arr[i] = arr[i].replace(" ","");
}
}
}
return arr;
}
Once the code steps out of stripEmail, the argument email is changed to the result. I've notice this happening in some other functions as well. This is resulting in strange problems when I try to use the variables.
Variable testemail set:
Once I step over the function, testemail is changed.
Avoid setting one array equal to another array if you want to avoid changing the original array. Instead of reusing the email variable, create a new output variable. In the code below, the emails are put into a new array named result.
The stripEmail function handles both a string and an array, and always returns an array that is different than the source array, leaving the original array unchanged.
The code can be changed to:
function test1() {
var testemail = ["Steve<steve#steve.com>","displayname<display#steve.com>"];
Logger.log('testemail: ' + testemail)
var debug = stripEmail(testemail);
Logger.log('debug: ' + debug)
Logger.log('testemail: ' + testemail)
}
function stripEmail(email) {
var arr,i,part1,result;
result = [];
//Give me an email with a display name and I will strip out the display name
//"<Steve Gon> stevegon#google.com"
if (typeof email === 'string') {
email = email.split(",");
}
for (i=0; i<email.length; i++) {
if (email[i].search("<")>-1) {//If there is no less than, then it doesn't have a display name
part1 = email[i].split("<");
if (part1.length == 2) {
result[i] = part1[1].replace(">","");
result[i] = result[i].replace("<","");
result[i] = result[i].replace(" ","");
}
}
}
return result;
}

Javascript Function to split and return a value from a string

I am trying to grab a certain value. I am new to javascript and I can't figure out why this is not working.
If I parse "kid_2" I should get "kostas". Instead of "Kostas" I always get "02-23-2000". So I must have a logic problem in the loop but I am really stuck.
function getold_val(fieldname,str){
var chunks=str.split("||");
var allchunks = chunks.length-1;
for(k=0;k<allchunks;k++){
var n=str.indexOf(fieldname);
alert(chunks[k]);
if(n>0){
var chunkd=chunks[k].split("::");
alert(chunkd);
return chunkd[1];
}
}
}
var test = getold_val('kid_2','date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||');
alert(test);
A regex may be a little more appealing. Here's a fiddle:
function getValue(source, key){
return (new RegExp("(^|\\|)" + key + "::([^$\\|]+)", "i").exec(source) || {})[2];
}
getValue("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","kid_2");
But if you want something a little more involved, you can parse that string into a dictionary like so (fiddle):
function splitToDictionary(val, fieldDelimiter, valueDelimiter){
var dict = {},
fields = val.split(fieldDelimiter),
kvp;
for (var i = 0; i < fields.length; i++) {
if (fields[i] !== "") {
kvp = fields[i].split(valueDelimiter);
dict[kvp[0]] = kvp[1];
}
}
return dict;
}
var dict = splitToDictionary("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","||","::");
console.log(dict["date_1"]);
console.log(dict["date_2"]);
console.log(dict["kid_1"]);
console.log(dict["kid_2"]);​
This works, here's my fiddle.
function getold_val(fieldname,str) {
var chunks = str.split('||');
for(var i = 0; i < chunks.length-1; i++) {
if(chunks[i].indexOf(fieldname) >= 0) {
return(chunks[i].substring(fieldname.length+2));
}
}
}
alert(getold_val('kid_2', 'date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||'));
The issue with your code was (as #slebetman noticed as well) the fact that a string index can be 0 because it starts exactly in the first letter.
The code is almost the same as yours, I just didn't use the second .split('::') because I felt a .substring(...) would be easier.
There are two bugs. The first error is in the indexOf call:
var n = str.indexOf(fieldname);
This will always return a value greater than or equal to 0 since the field exists in the string. What you should be doing is:
var n = chunks[k].indexOf(fieldname);
The second error is in your if statement. It should be:
if(n >= 0) {
...
}
or
if(n > -1) {
...
}
The substring you are looking for could very well be the at the beginning of the string, in which case its index is 0. indexOf returns -1 if it cannot find what you're looking for.
That being said, here's a better way to do what you're trying to do:
function getold_val(fieldName, str) {
var keyValuePairs = str.split("||");
var returnValue = null;
if(/||$/.match(str)) {
keyValuePairs = keyValuePairs.slice(0, keyValuePairs.length - 1);
}
var found = false;
var i = 0;
while(i < keyValuePairs.length && !found) {
var keyValuePair = keyValuePairs[i].split("::");
var key = keyValuePair[0];
var value = keyValuePair[1];
if(fieldName === key) {
returnValue = value;
found = true;
}
i++;
}
return returnValue;
}

javascript summing up array

I`m trying to sum the values of the elements in an array using javascript, this is my script.
function sumAll()
{
var totalOverheads = 0;
var overheads = new Array();
overheads = document.getElementsByName('overhead');
for(i=0;i<overheads.length;i++)
if(!isNaN(overheads[i].value) || overheads[i].value != null || overheads[i].value != "" || overheads[i].value != '' || overheads[i].value != NULL)
alert(overheads[i].value);
//totalOverheads = parseInt(totalOverheads) + parseInt(overheads[i].value);
alert(totalOverheads);
}
for now, in the if condition inside the for loop, I`m displaying the value of the item in an alert, yet it`s not working correctly, it just displays all the items even if the item is not a number, how can I perform an operation if the input is only a number?
getElementsByName returns a NodeList. Not sure if that was the problem, but anyway:
var totalOverheads = 0;
var overheads = document.getElementsByName('overhead');
var n;
var i; // <<--- don't forget to initialise i
for (i = 0; i < overheads.length; ++i) {
n = parseInt(overheads.item(i).value, 10);
if (!isNaN(n)) {
totalOverheads += n;
}
}
alert(totalOverheads);
Also, please use brackets!

Categories

Resources