getting undefined from a function - javascript

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.

Related

How can I extract all contained characters in a String? [duplicate]

I have a string with repeated letters. I want letters that are repeated more than once to show only once.
Example input: aaabbbccc
Expected output: abc
I've tried to create the code myself, but so far my function has the following problems:
if the letter doesn't repeat, it's not shown (it should be)
if it's repeated once, it's show only once (i.e. aa shows a - correct)
if it's repeated twice, shows all (i.e. aaa shows aaa - should be a)
if it's repeated 3 times, it shows 6 (if aaaa it shows aaaaaa - should be a)
function unique_char(string) {
var unique = '';
var count = 0;
for (var i = 0; i < string.length; i++) {
for (var j = i+1; j < string.length; j++) {
if (string[i] == string[j]) {
count++;
unique += string[i];
}
}
}
return unique;
}
document.write(unique_char('aaabbbccc'));
The function must be with loop inside a loop; that's why the second for is inside the first.
Fill a Set with the characters and concatenate its unique entries:
function unique(str) {
return String.prototype.concat.call(...new Set(str));
}
console.log(unique('abc')); // "abc"
console.log(unique('abcabc')); // "abc"
Convert it to an array first, then use Josh Mc’s answer at How to get unique values in an array, and rejoin, like so:
var nonUnique = "ababdefegg";
var unique = Array.from(nonUnique).filter(function(item, i, ar){ return ar.indexOf(item) === i; }).join('');
All in one line. :-)
Too late may be but still my version of answer to this post:
function extractUniqCharacters(str){
var temp = {};
for(var oindex=0;oindex<str.length;oindex++){
temp[str.charAt(oindex)] = 0; //Assign any value
}
return Object.keys(temp).join("");
}
You can use a regular expression with a custom replacement function:
function unique_char(string) {
return string.replace(/(.)\1*/g, function(sequence, char) {
if (sequence.length == 1) // if the letter doesn't repeat
return ""; // its not shown
if (sequence.length == 2) // if its repeated once
return char; // its show only once (if aa shows a)
if (sequence.length == 3) // if its repeated twice
return sequence; // shows all(if aaa shows aaa)
if (sequence.length == 4) // if its repeated 3 times
return Array(7).join(char); // it shows 6( if aaaa shows aaaaaa)
// else ???
return sequence;
});
}
Using lodash:
_.uniq('aaabbbccc').join(''); // gives 'abc'
Per the actual question: "if the letter doesn't repeat its not shown"
function unique_char(str)
{
var obj = new Object();
for (var i = 0; i < str.length; i++)
{
var chr = str[i];
if (chr in obj)
{
obj[chr] += 1;
}
else
{
obj[chr] = 1;
}
}
var multiples = [];
for (key in obj)
{
// Remove this test if you just want unique chars
// But still keep the multiples.push(key)
if (obj[key] > 1)
{
multiples.push(key);
}
}
return multiples.join("");
}
var str = "aaabbbccc";
document.write(unique_char(str));
Your problem is that you are adding to unique every time you find the character in string. Really you should probably do something like this (since you specified the answer must be a nested for loop):
function unique_char(string){
var str_length=string.length;
var unique='';
for(var i=0; i<str_length; i++){
var foundIt = false;
for(var j=0; j<unique.length; j++){
if(string[i]==unique[j]){
foundIt = true;
break;
}
}
if(!foundIt){
unique+=string[i];
}
}
return unique;
}
document.write( unique_char('aaabbbccc'))
In this we only add the character found in string to unique if it isn't already there. This is really not an efficient way to do this at all ... but based on your requirements it should work.
I can't run this since I don't have anything handy to run JavaScript in ... but the theory in this method should work.
Try this if duplicate characters have to be displayed once, i.e.,
for i/p: aaabbbccc o/p: abc
var str="aaabbbccc";
Array.prototype.map.call(str,
(obj,i)=>{
if(str.indexOf(obj,i+1)==-1 ){
return obj;
}
}
).join("");
//output: "abc"
And try this if only unique characters(String Bombarding Algo) have to be displayed, add another "and" condition to remove the characters which came more than once and display only unique characters, i.e.,
for i/p: aabbbkaha o/p: kh
var str="aabbbkaha";
Array.prototype.map.call(str,
(obj,i)=>{
if(str.indexOf(obj,i+1)==-1 && str.lastIndexOf(obj,i-1)==-1){ // another and condition
return obj;
}
}
).join("");
//output: "kh"
<script>
uniqueString = "";
alert("Displays the number of a specific character in user entered string and then finds the number of unique characters:");
function countChar(testString, lookFor) {
var charCounter = 0;
document.write("Looking at this string:<br>");
for (pos = 0; pos < testString.length; pos++) {
if (testString.charAt(pos) == lookFor) {
charCounter += 1;
document.write("<B>" + lookFor + "</B>");
} else
document.write(testString.charAt(pos));
}
document.write("<br><br>");
return charCounter;
}
function findNumberOfUniqueChar(testString) {
var numChar = 0,
uniqueChar = 0;
for (pos = 0; pos < testString.length; pos++) {
var newLookFor = "";
for (pos2 = 0; pos2 <= pos; pos2++) {
if (testString.charAt(pos) == testString.charAt(pos2)) {
numChar += 1;
}
}
if (numChar == 1) {
uniqueChar += 1;
uniqueString = uniqueString + " " + testString.charAt(pos)
}
numChar = 0;
}
return uniqueChar;
}
var testString = prompt("Give me a string of characters to check", "");
var lookFor = "startvalue";
while (lookFor.length > 1) {
if (lookFor != "startvalue")
alert("Please select only one character");
lookFor = prompt(testString + "\n\nWhat should character should I look for?", "");
}
document.write("I found " + countChar(testString, lookFor) + " of the<b> " + lookFor + "</B> character");
document.write("<br><br>I counted the following " + findNumberOfUniqueChar(testString) + " unique character(s):");
document.write("<br>" + uniqueString)
</script>
Here is the simplest function to do that
function remove(text)
{
var unique= "";
for(var i = 0; i < text.length; i++)
{
if(unique.indexOf(text.charAt(i)) < 0)
{
unique += text.charAt(i);
}
}
return unique;
}
The one line solution will be to use Set. const chars = [...new Set(s.split(''))];
If you want to return values in an array, you can use this function below.
const getUniqueChar = (str) => Array.from(str)
.filter((item, index, arr) => arr.slice(index + 1).indexOf(item) === -1);
console.log(getUniqueChar("aaabbbccc"));
Alternatively, you can use the Set constructor.
const getUniqueChar = (str) => new Set(str);
console.log(getUniqueChar("aaabbbccc"));
Here is the simplest function to do that pt. 2
const showUniqChars = (text) => {
let uniqChars = "";
for (const char of text) {
if (!uniqChars.includes(char))
uniqChars += char;
}
return uniqChars;
};
const countUnique = (s1, s2) => new Set(s1 + s2).size
a shorter way based on #le_m answer
let unique=myArray.filter((item,index,array)=>array.indexOf(item)===index)

How to fix this "if" statement

I don't really know the correct format to this if statement. I want it to count the frequency each word in my txt file was used.
function countWords(array, word, index) {
var count = 0;
var value = " "
for (var i = 0; i < array.length; i++) {
if (array[i] == 0 && value == word)
count++;
}
}
if (getUserSelectionForm.problem.value == "pay") {
countWords(working2DArray, "pay", 0)
if (getUserSelectionForm.problem.value == "staffing") {
countWords(working2DArray, "staffing", 0)
if (getUserSelectionForm.problem.value == "hours") {
countWords(working2DArray, "hours", 0)
if (getUserSelectionForm.problem.value == "management") {
countWords(working2DArray, "management", 0)
console.log(countWords)
document.getElementById('section2').innerHTML = "The selected word appears " + countWords + " times in the array."
}
Try not to use multiple IF statements and use a switch statement instead. Makes code much clearer and cleaner.
E.g.
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
So:
var p = getUserSelectionForm.problem.value;
switch (p) {
case 'pay':
countWords(working2DArray, "pay", 0);
break;
case 'staffing':
countWords(working2DArray, "staffing", 0);
}
You are making three mistakes in code:
You are missing some of the closing curly braces } of you if blocks.
You do not return anything from function. You should return count.
countWords is a function you don't need to display that. You need to display its result.
You can make your code much simpler. You don't need these if statements at all because you are passing the same value of getUserSelectionForm.problem.value to the function so directly pass it.
function countWords(array, word, index) {
var count = 0;
var value= " "
for(var i = 0; i < array.length; i++){
if(array[i] == 0 && value == word)
count++;
}
return count;
}
let word = getUserSelectionForm.problem.value
document.getElementById('section2').innerHTML = `The selected word appears ${countWords(working2DArray,word,0)} times in array`
If you want to only check for few items then use create a array of "pay","staffing"... and use includes() on it
let word = getUserSelectionForm.problem.value
if(["pay","staffing","hours","management"].includes(word)){
document.getElementById('section2').innerHTML = `The selected word appears ${countWords(working2DArray,word,0)} times in array`
}
In my understanding , you want to trigger the function whenever problem.value ==='pay'||'staffing'||'hours'||'management' ,here is clearer version for your reference:
var problemValue = getUserSelectionForm.problem.value;
var isProblemValueMatch = ["pay", "staffing" ,"hours", "management"].includes(problemValue);
if (isProblemValueMatch ) {
var countWords = working2DArray.filter(function(v) {
return v === problemValue;
}).length;
console.log(countWords)
document.getElementById('section2').innerHTML = "The selected word appears " + countWords + " times in the array."
}

Why does the second array remain empty?

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();

Calculating the length of an array of regular expressions

I have a function here that is meant to check an element against a given array of regular expressions. The array that I am passing contains ten different regular expressions.
var regExAlphabet = /[a-z]/;
var regExNumbers = /[0-9]/;
var regExWhile = /while/;
var regExIf = /if/;
var regExElse = /else/;
var regExTrue = /true/;
var regExFalse = /false/;
var regExInt = /int/;
var regExString = /string/;
var regExBoolean = /boolean/;
var regexList = [regExAlphabet, regExNumbers, regExTrue, regExFalse,
regExInt, regExString, regExBoolean, regExWhile, regExIf, regExElse];
function loopThroughOptions(regexList, element) {
for (var i = 0; i < regexList.length; i++)
failSafe(regexList[i], element) // failSafe is defined but not shown
}
var aString = "a";
loopThroughOptions(regexList, aString);
When I run this, I am getting an uncaught typeError: cannot read property length of undefined in my loopThroughOptions function. Why is this happening? How can I fix it?
EDIT: It looks like I will need to post the failSafe function. It is quite long. Take a stab at it.
var tokenList = []; // list of discovered tokens
var substringsArray = []; // any strings that are not tokens go here
function substringsHandler(array) {
for (var i = 0; i < substringsArray.length; i++) {
for (var y = 0; y < regexList.length; y++) {
failSafe(regexList[y], substringsArray[i])
}
}
}
function findAMatch(value) {
if (value == "a")
console.log("matched a");
}
function findACharMatch(value) {
if (value == "a")
console.log("matched a");
}
function failSafe(regEx, element) {
if (regEx.test(element) && element.length > 1) { // if the token is there
var x = regEx.exec(element); // give us more information on the element
var value = x["0"]; // keep track of the value of the token
var index = x.index; // keep track of the index
var substring = value;
console.log(index);
console.log(substring.length);
console.log(element.length);
tokenList.push({
value: substring,
indexFound: index});
console.log(tokenList[0]);
if (index > 0 && index + substring.length - 1 < element.length) { // if we found a token in the middle of a string
console.log("Found token in the middle of the string.");
substringsArray.push({ // give us the half that comes before the match
value: element.substring(0, index),
indexFound: 0
});
substringsArray.push({ // give us the rest of the string that occurs after the match
value: element.substring(index + value.length),
indexFound: index + value.length
});
substringsHandler(substringsArray);
// all successful token finds get sent to tokenList to search for a match
// if nothing is found, then everything gets translated to characters or digits
} else if (index > 0 && index + substring.length - 1 == element.length) { // if there is more string to the left only
console.log("Found token on the right of the string.");
substringsArray.push({
value: element.substring(0, index), // compare these values using find a match later
indexFound: 0
})
} else if (index == 0 && substring.length < element.length) { // if there is more string to the right only
console.log("Found token on the left of the string.");
substringsArray.push({
value: element.substring(substring.length),
indexFound: substring.length
})
} else { // the token is the only input
console.log("The token consists of the entire string.");
}
} else if (regEx.test && element.length == 1) {
var x = regEx.exec(element); // give us more information on the element
var value = x["0"]; // keep track of the value of the token
var index = x.index; // keep track of the index
var substring = value;
tokenList.push({
value: value,
index: index
})
} else {
console.log("No match for regexp " + regEx + "trying the next one...");
return;
}
console.log(tokenList);
tokenList.sort(function(a, b) {
return a.indexFound - b.indexFound;
});
console.log(tokenList);
for (var i = 0; i < tokenList.length; i++) {
if (tokenList[i].value.length > 1)
findAMatch(tokenList[i].value);
else
findACharMatch(tokenList[i].value);
}
};
Ok, so I ran all of your showed code and it has an error, according to RegExp docs
If the match fails, the exec() method returns null.
So, in your code, you always take for granted that regEx.exec(element); will return an array (it supposes that the RegExp will match at least one element), which, at least in your examples, is false, and you are not handling that.
In short, the easiest way to get rid of this is by returning if x is null:
var x = regEx.exec(element);
if (!x) return // add this
Tested it, and no problem was thrown, only console output was matched a

What's the best way to count keywords in JavaScript?

What's the best and most efficient way to count keywords in JavaScript? Basically, I'd like to take a string and get the top N words or phrases that occur in the string, mainly for the use of suggesting tags. I'm looking more for conceptual hints or links to real-life examples than actual code, but I certainly wouldn't mind if you'd like to share code as well. If there are particular functions that would help, I'd also appreciate that.
Right now I think I'm at using the split() function to separate the string by spaces and then cleaning punctuation out with a regular expression. I'd also want it to be case-insensitive.
Cut, paste + execute demo:
var text = "Text to be examined to determine which n words are used the most";
// Find 'em!
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
// Sort 'em!
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
// Come back any time, straaanger!
var n = 10;
var message = ["The top " + n + " words are:"];
for (var i = 0; i < n; i++)
{
message.push(wordList[i][0] + " - " + wordList[i][1] + " occurance" +
(wordList[i][1] == 1 ? "" : "s"));
}
alert(message.join("\n"));
Reusable function:
function getTopNWords(text, n)
{
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
var topWords = [];
for (var i = 0; i < n; i++)
{
topWords.push(wordList[i][0]);
}
return topWords;
}
Once you have that array of words cleaned up, and let's say you call it wordArray:
var keywordRegistry = {};
for(var i = 0; i < wordArray.length; i++) {
if(keywordRegistry.hasOwnProperty(wordArray[i]) == false) {
keywordRegistry[wordArray[i]] = 0;
}
keywordRegistry[wordArray[i]] = keywordRegistry[wordArray[i]] + 1;
}
// now keywordRegistry will have, as properties, all of the
// words in your word array with their respective counts
// this will alert (choose something better than alert) all words and their counts
for(var keyword in keywordRegistry) {
alert("The keyword '" + keyword + "' occurred " + keywordRegistry[keyword] + " times");
}
That should give you the basics of doing this part of the work.
Try to split you string on words and count the resulting words, then sort on the counts.
This builds upon a previous answer by insin by only having one loop:
function top_words(text, n) {
// Split text on non word characters
var words = text.toLowerCase().split(/\W+/)
var positions = new Array()
var word_counts = new Array()
for (var i=0; i<words.length; i++) {
var word = words[i]
if (!word) {
continue
}
if (typeof positions[word] == 'undefined') {
positions[word] = word_counts.length
word_counts.push([word, 1])
} else {
word_counts[positions[word]][1]++
}
}
// Put most frequent words at the beginning.
word_counts.sort(function (a, b) {return b[1] - a[1]})
// Return the first n items
return word_counts.slice(0, n)
}
// Let's see if it works.
var text = "Words in here are repeated. Are repeated, repeated!"
alert(top_words(text, 3))
The result of the example is: [['repeated',3], ['are',2], ['words', 1]]
I would do exactly what you have mentioned above to isolate each word. I would then probably add each word as the index of an array with the number of occurrences as the value.
For example:
var a = new Array;
a[word] = a[word]?a[word]+1:1;
Now you know how many unique words there are (a.length) and how many occurrences of each word existed (a[word]).

Categories

Resources