How can I shortened this? - javascript

I am trying to self teach myself programming and started with javascript. To learn more I have been completing challenges to practice and one challenge was to write a script that would determine the first case of the word in a string with the most repeated letters. I was able to complete it with this code I made:
string = "Hey i believe";
string = string.split(" ");
stringarray = [];
longestlength = 0;
for (i = 0; i < string.length; i++) {
stringarray.push(0);
}
for (i = 0; i < string.length; i++) {
if (string[i].length > longestlength) {
longestlength = string[i].length;
longestword = string[i];
}
}
for (x = 0; x < string.length; x++) {
y = 0;
z = 0;
while (z < string[x].length) {
if (string[x].substr(z,1) == string[x].substr(y,1) && z !== y) {
stringarray[x] += 1;
y = string[x].length -1;
}
y++;
if (y == string[x].length) {
z++;
y = z;
}
}
}
if (Math.max.apply(null,stringarray) === 0) {
mostrptltword = -1;
}
else {
mostrptltword = string[stringarray.indexOf(Math.max.apply(null,stringarray))];
}
console.log(mostrptltword);
But to get all the points possible for the challenge it must be completed in less than 10 minutes this took me 25 mins. So my question is am I over complicating things; causing me to write a much longer script than needed? I have read a little bit about things like Regular Expressions and how they can really shortened script lengths and the time it takes to write them would that or maybe another technique of been more useful than all the loops I had to make?

var words = "Heyyyyy I believe".split(' '); // split the words into an array
var values = [], // total of times that a letter appears
k = 0, // 'global' counter. I'm using this to iterate over the values array
heigher = 0, // holds de heigher occurrence of a letter
letter = ""; // the letter that most appears in that word
word = ""; // the word
// iterate over all the words
for(var i = 0; i < words.length; i++) {
// iterate over each letter in each word
for(var j = 0; j < words[i].length; j++) {
// holds the occurrence time
// RegEx: get the word in the position 'i' and check how many times the letter appears on the position [j] appears
values[k] = words[i].match(new RegExp(words[i][j],'g')).length;
// check if the next letter appears more times than the previous one
if(values[k] > heigher) {
// hold the values of interest
heigher = values[k];
letter = words[i][j];
word = words[i];
}
k++;
}
}
console.log("word: " + word + " letter: " + letter + " total: " + heigher);
jsfiddle: http://jsfiddle.net/felipemiosso/FyCHG/
The is commented. Hope it helps :)

Related

Parsing out all Special Characters

I'll preface my question by saying I know using strictly regex for this is a lot easier/cleaner of a solution and I plan on refactoring my code to do just that.
That said, I wanted to see if my brute force way could actually work.
Basically, this is a simple letter substitution cipher that replaces a letter with the letter 13 letters after it in the alphabet.
If the letter is a special character, it keeps that special character.
I have my function returning the correct letters and have some regex code in there to check for special characters but it keeps saying it is finding 13 occurrences of a special character and I can't seem to figure out why. Any thoughts?
function rot13(message) {
let alpha = "abcdefghijklmnopqrstuvwxyz"
let capAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let special = /[ !##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]/g;
let arrAlpha = alpha.split("")
let messageSplit = message.split("")
let sum = 0
let newSum = 0
let answer = []
for (let i = 0; i < message.length; i++) {
for (let j = 0; j < alpha.length; j++) {
if (message[i] === alpha[j]) {
if (j <= 12) {
answer.push(alpha[j + 13])
} else {
sum = 25 - j
newSum = 12 - sum
answer.push(alpha[newSum]);
sum = 0
}
} else if (message[i] === capAlpha[j]) {
if (j <= 12) {
answer.push(capAlpha[j + 13])
} else {
sum = 25 - j
newSum = 12 - sum
answer.push(capAlpha[newSum]);
sum = 0
}
} else if (special.test(message[i])) {
console.log("hello");
answer.push(message[i])
}
}
}
return (answer.join(""));
}
console.log(rot13("Hello"));
console.log("---------------");
rot13("Hello World!");
The problem appears to be in this snippet:
else if (special.test(message[i])) {
console.log("hello");
answer.push(message[i])
}
Because you're looping over the length of alpha, it's executing that check 13 times, and thus pushing the space into answer 13 times. If you add break; after the push, it'll exit the j loop and proceed to the next iteration of the i loop.

Whats wrong with my palindrome? (javascript)

I have written this js code for palindrome, I know there are better and more efficient palindrome methods online but I want to know why I am unable to get my palindrome function to work properly?
CODE:
var pal = function(str) {
var len = str.length;
for (var i = 0; i < len; i++) {
var comp1 = str.substring(i, i + 1);
for (var j = len; j > 0; j--) {
var comp2 = str.substring(j - 1, j);
}
if (comp1 != comp2) {
console.log("not palindrome")
break;
} else {
console.log('palindrome')
}
}
}
pal('maddog');
OUTPUT :
palindrome
not palindrome
There are lot of better algorithms to check Palindrome. Let use the similar algorithm that you are using.
We basically use two pointers - left and right, and move to middle at the same time. In the original question, left pointer and right pointer doesn't move at the same time.
Pointers should move like this -
a b c b a
^ ^
a b c b a
^ ^
a b c b a
^
var isPalindrome = function (str) {
for (var i = 0, j = str.length-1; i < j; i++ , j--) {
if (str[i] != str[j]) {
return false;
}
}
return true;
}
console.log('maddog : ' + isPalindrome('maddog'));
console.log('abcba : ' + isPalindrome('abcba'));
console.log('deed : ' + isPalindrome('deed'));
console.log('a : ' + isPalindrome('a'));
Try the following code. It works by dividing the string length by 2, and then iterating up, checking mirroring characters against each other:
var pal = function(str){
var len = str.length;
for(var i = 0; i < Math.floor(len/2); i++){
if(str[i] != str[(len-1)-i]){
return false;
}
}
return true;
}
console.log(pal("bunny"));
console.log(pal("amoreroma"));
The inner loop is totally unnecessary. It does the same thing every time -- it loops through the whole string, starting from the end, repeatedly setting comp2 to the character; when it's done, comp2 always contains the first character. So your function just tests whether every character in the string is the same as the first character.
To test if something is a palindrome, you need to compare each character with the corresponding character from the other end of the string. You don't need two loops for this. You also only need to loop through the first half of the string, not the whole string.
Finally, you should only echo Palindrome at the end of the loop. Inside the loop you only know that one character matches, not all of them.
var pal = function(str) {
var len = str.length;
var half = Math.floor(len / 2);
var isPal = true;
for (var i = 0; i < half; i++) {
var comp1 = str[i];
var comp2 = str[len - i - 1];
if (comp1 != comp2) {
console.log("not palindrome")
isPal = false;
break;
}
}
if (isPal) {
console.log('palindrome')
}
}
pal('maddog');
pal('maddam');
You don't really need the nested loops, you can just loop backwards through the string to invert the string and then compare it to the original string. I updated the Snippet to work.
Before, your code was not inverting the string but rather just iterating through the characters and assigning them to the comp1 and comp1 variables. You need to concatenate the strings in order to build the new string backwards comp = comp + str.substring(j-1, j);
var pal = function(str) {
var len = str.length;
var comp = '';
for (var j = len; j > 0; j--) {
comp = comp + str.substring(j - 1, j);
}
if (str !== comp) {
console.log("not palindrome")
return;
}
console.log('palindrome')
}
pal('arepera');

How to reverse a string in a specific way

This is a very specific question and I want to reverse a string in this way however I don't know how to go about it.
What i want to do is take a word lets say 'hello'. olleh
and take the first and last letters and output 'oellh' then doing the same thing for the next two characters so 'e' and 'l' which would then output 'olleh'.
So to summaries this I need to reverse the first and last character and then the same thing for the second characters until i get to the middle character.
This must use a for loop.
reverse('hello');
function reverse(string) {
var character = [];
for (var i = string.length -1; i >= 0; i--) {
character.push(string[i]);
}
console.log(character.join(""));
}
Let me know if this needs further explanation
This might do the trick:
function replaceAt(string, index, character){
return string.substr(0, index) + character + string.substr(index+character.length);
}
function reverse(string) {
var len = string.length;
len = len/2;
var s = string;
for (var i = 0; i < len ; i++)
{
var m = s[string.length-i-1];
var k = s[i];
s = replaceAt(s,i, m);
s = replaceAt(s, string.length-i-1, k);
}
return s;
}
You can easily reverse a string doing:
"hello".split("").reverse().join("")

Return the first word with the greatest number of repeated letters

This is a question from coderbyte’s easy set. Many people asked about it already, but I’m really curious about what’s wrong with my particular solution (I know it’s a pretty dumb and inefficient one..)
Original question:
Have the function LetterCountI(str) take the str parameter being passed and return the first word with the greatest number of repeated letters. For example: "Today, is the greatest day ever!" should return greatest because it has 2 e's (and 2 t's) and it comes before ever which also has 2 e's. If there are no words with repeating letters return -1. Words will be separated by spaces.
My solution works most of the time. But if it seems the last word of the input isn’t valued by my code. For example, for “a bb ccc”, “bb” will be returned instead of “ccc”. But the funny thing here is if the string only contains one word, the result is correct. For example, “ccc” returns “ccc”.
Please tell me where I was wrong. Thank you in advance!
function LetterCountI(str) {
str.toLowerCase();
var arr = str.split(" ");
var count = 0;
var word = "-1";
for (var i = 0; i < arr.length; i++) {
for (var a = 0; a < arr[i].length; a++) {
var countNew = 0;
for (var b = a + 1; b < arr[i].length; b++) {
if(arr[i][a] === arr[i][b])
countNew += 1;
}
if (countNew > count) {
count = countNew;
word = arr[i];
}
}
return word;
}
}
Please find below the workable version of your code:
function LetterCountI(str) {
str = str.toLowerCase();
var arr = str.split(" ");
var count = 0;
var word = "-1";
for (var i = 0; i < arr.length; i++) {
for (var a = 0; a < arr[i].length; a++) {
var countNew = 0;
for (var b = a + 1; b < arr[i].length; b++) {
if (arr[i][a] === arr[i][b])
countNew += 1;
}
if (countNew > count) {
count = countNew;
word = arr[i];
}
}
}
return word;
}
Here is the Java code soln for your problem.
You have returned your answer incorrectly. You should have returned word/Answer/res out of "for loops".
Check my chode here.
public static String StringChallenge( String str) {
String[] arr = str.split(" ");
int count = 0; String res = "-1";
for (int i = 0; i < arr.length ; i++) {
for (int j = 0; j < arr[i].length() ; j++) {
int counter = 0;
for (int k = j + 1; k < arr[i].length() ; k++) {
if(arr[i].charAt(j) === arr[i].charAt(k) )
counter ++;
}
if (counter > count) {
count = counter; res = arr[i];
}
}
return res;
}
}
I think the problem is that you're placing the return statement inside your outermost loop. It should be inside your inner loop.
So you have to place the return statement within the inner loop.
Correct use of return
if (countNew > count) {
count = countNew;
word = arr[i];
}
return word;
}
}
}
You need to move the return word; statement outside of the loop to fix your version.
I also put together another take on the algorithm that relies on a few built in javascript methods like Array.map and Math.max, just for reference. I ran a few tests and it seems to be a few milliseconds faster, but not by much.
function LetterCountI(str) {
var maxCount = 0;
var word = '-1';
//split string into words based on spaces and count repeated characters
str.toLowerCase().split(" ").forEach(function(currentWord){
var hash = {};
//split word into characters and increment a hash map for repeated values
currentWord.split('').forEach(function(letter){
if (hash.hasOwnProperty(letter)) {
hash[letter]++;
} else {
hash[letter] = 1;
}
});
//covert the hash map to an array of character counts
var characterCounts = Object.keys(hash).map(function(key){ return hash[key]; });
//find the maximum value in the squashed array
var currentMaxRepeatedCount = Math.max.apply(null, characterCounts);
//if the current word has a higher repeat count than previous max, replace it
if (currentMaxRepeatedCount > maxCount) {
maxCount = currentMaxRepeatedCount;
word = currentWord;
}
});
return word;
}
Yet another solution in a more functional programming style:
JavaScript
function LetterCountI(str) {
return ((str = str.split(' ').map(function(word) {
var letters = word.split('').reduce(function(map, letter) {
map[letter] = map.hasOwnProperty(letter) ? map[letter] + 1 : 1;
return map;
}, {}); // map of letters to number of occurrences in the word
return {
word: word,
count: Object.keys(letters).filter(function(letter) {
return letters[letter] > 1;
}).length // number of repeated letters
};
}).sort(function(a, b) { // Sort words by number of repeated letters
return b.count - a.count;
}).shift()) && str.count && str.word) || -1; // return first word with maximum repeated letters or -1
}
console.log(LetterCountI('Today, is the greatest day ever!')); // => greatest
Plunker
http://plnkr.co/edit/BRywasUkQ3KYdhRpBfU2?p=preview
I recommend use regular expression: /a+/g to find a list of letter with a key word a.
My example :
var str = aa yyyyy bb cccc cc dd bbb;
Fist, find a list of different word :
>>> ["a", "y", "b", "c", "d"]
Use regular expression for each word in list of different word :
var word = lstDiffWord[1];
var
wordcount = str.match(new RegExp(word+'+','g'));
console.log(wordcount);
>>>>["yyyyy"]
Here is full example: http://jsfiddle.net/sxro0sLq/4/

Algorithm of the greatest intersect of word in set of words

The story behind
I am creating a voice controlled application using x-webkit-speech which is surprisingly good (the feature, not my app), but sometimes the user (me) mumbles a bit. It would be nice to accept the command if some reasonable part of the word matches some reasonable part of some reasonable command. So I search for the holy grail called Algorithm of the Greatest Intersect of Word in Set of Words. Could some fresh bright mind drive me out of the cave of despair?
Example
"rotation" in ["notable","tattoo","onclick","statistically"]
should match tattoo because it has the longest intersect with rotation (tat_o). statistically is the second best (tati intersect), because longer part of the word needs to be ignored (but this is bonus condition, it would be acceptable without it).
Notes
I use Czech language where the pronunciation is very close to its written form
javascript is the preffered language, but any pseudocode is acceptable
the minimal length of the intersect should be a parameter of the algorithm
What have I tried?
Well, it is pretty embarassing....
for(var i=10; i>=4; --i) // reasonable substring
for(var word in words) // for all words in the set
for(var j=0; j<word.length-i; ++j) // search for any i substring
// aaargh... three levels of abstraction is too much for me
This is an algorithm that seems to work. I have no idea how good it performs compared to other already established algorithms (I suspect it perform worse) but maybe it gives you an idea how you could do it:
FIDDLE
var minInt = 3;
var arr = ["notable","tattoo","onclick","statistically"];
var word = "rotation";
var res = [];
if (word.length >= minInt) {
for (var i = 0; i < arr.length; i++) {
var comp = arr[i];
var m = 0;
if (comp.length >= minInt) {
for (var l = 0; l < comp.length - minInt + word.length - minInt + 1; l++) {
var subcomp = l > word.length - minInt ? comp.substring(l - word.length + minInt) : comp;
var subword = l < word.length - minInt ? word.substring(word.length - minInt - l) : word;
var minL = Math.min(subcomp.length, subword.length);
var matches = 0;
for (var k = 0; k < minL; k++) {
if (subcomp[k] === subword[k]) {
matches++;
}
}
if (matches > m) {
m = matches;
}
}
}
res[i] = m >= minInt ? m : null;
}
}
console.log(res);
What happens is, that it compares the two strings by "moving" on against the other and calculates the matching letters in each position. Here you see the compared "sub"words for rotation vs. notable:
ion / notable --> one match on index 1
tion / notable --> no match
ation / notable --> no match
tation / notable --> one match on index 2
otation / notable --> no match
rotation / notable --> three matches on index 1,2,3
rotation / otable --> no match
rotation / table --> no match
rotation / able --> no match
rotation / ble --> no match
As you see, the maximum number of matches is 3 and that is what it would return.
Here's an implementation of a Levenshtein Distance Calculator in Javascript.
It returns an object containing the matching command and distance.
var commandArr = ["cat", "dog", "fish", "copy", "delete"]
var testCommand = "bopy";
function closestMatch(str, arr)
{
//console.log("match called");
var matchDist = [];
var min, pos;
for(var i=0; i<arr.length; i++)
{
matchDist[i]=calcLevDist(str, arr[i]);
console.log("Testing "+ str + " against " + arr[i]);
}
//http://stackoverflow.com/questions/5442109/how-to-get-the-min-elements-inside-an-array-in-javascript
min = Math.min.apply(null,matchDist);
pos = matchDist.indexOf(min);
var output = { match : arr[pos],
distance : matchDist[pos]
};
return output;
}
function calcLevDist (str1, str2)
{
//console.log("calc running");
var cost = 0 , len1, len2;
var x = 1;
while(x > 0)
{
len1 = str1.length;
console.log("Length of String 1 = " + len1);
len2 = str2.length;
console.log("Length of String 2 = " + len2);
if(len1 == 0)
{
cost+= len2;
return cost;
}
if(len2 == 0)
{
cost+= len1;
return cost;
}
x = Math.min(len1,len2);
if(str1.charAt(len1 -1) != str2.charAt(len2 -1))
{
cost++;
}
else
console.log(str1.charAt(len1-1) + " matches " + str2.charAt(len2-1));
str1 = str1.substring(0, len1 -1 );
str2 = str2.substring(0, len2 -1 );
console.log("Current Cost = " + cost);
}
}
var matchObj = closestMatch(testCommand, commandArr);
var match = matchObj["match"];
var dist = matchObj["distance"];
$("#result").html("Closest match to " + testCommand + " = " + match + " with a Lev Distance of " + dist + "." )
You can mess around with the fiddle here.
Thank you basilikum and JasonNichols and also Mike and Andrew for the comments, it really helped me to finish the algorithm. I come up with my own brute force O(n^3) solution in case someone runs into this question with the same problem.
Anyone is invited to play with the fiddle to improve it.
The algorithm
/**
* Fuzzy match for word in array of strings with given accurancy
* #param string needle word to search
* #param int accurancy minimum matching characters
* #param array haystack array of strings to examine
* #return string matching word or undefined if none is found
*/
function fuzzyMatch(needle,accurancy,haystack) {
function strcmpshift(a,b,shift) {
var match=0, len=Math.min(a.length,b.length);
for(var i in a) if(a[i]==b[+i+shift]) ++match;
return match;
}
function strcmp(a,b) {
for(var i=0,max=0,now; i<b.length; ++i) {
now = strcmpshift(a,b,i);
if(now>max) max = now;
}
return max;
}
var word,best=accurancy-1,step,item;
for(var i in haystack) {
item = haystack[i];
step = Math.max(strcmp(item,needle),strcmp(needle,item));
if(step<=best) continue;
best=step, word=item;
};
return word;
}
Example
var word = "rotation";
var commands = ["notable","tattoo","onclick","statistically"];
// find the closest command with at least 3 matching characters
var command = fuzzyMatch(word,3,commands);
alert(command); // tattoo

Categories

Resources