I'm creating a kid's learning tool that has a form which matches 4 letters to a word.
I want to count the number of character matches in a word. But it counts duplicates of letters as 2 instead of 1. For example if the word is "loot", and the user submits "flop", the matching letters are 3 instead of 2, because it's counting "o" twice. How do I fix this? Many thanks
function countMatching(str1, str2) {
var c = 0;
for (var i = 0; i < str1.length; i++) {
if (str2.includes(str1[i]))
c += 1;
}
matchingLetters = c;
}
I made an alternative version of #cmgchess' answer, which creates an array of the actual solution of letters to still guess, and removes each letter as it is encountered in the entered solution.
let matchingLetters;
function countMatching(str1, str2) {
var c = 0;
str1Arr = str1.split('');
for (var i = 0; i < str2.length; i++) {
if (str1Arr.includes(str2[i])) {
c += 1;
str1Arr.splice(str1Arr.indexOf(str2[i]), 1);
}
}
matchingLetters = c;
}
countMatching('loot', 'boot')
console.log(matchingLetters)
A possible approach using Sets.
I converted the string into a set and back to an array
so if str1 is loot then str1Set will be ['l','o','t']. The rest is the same
let matchingLetters;
function countMatching(str1, str2) {
var c = 0;
str1Set = [...new Set([...str1])]
str2Set = [...new Set([...str2])]
for (var i = 0; i < str1Set.length; i++) {
if (str2Set.includes(str1Set[i]))
c += 1;
}
matchingLetters = c;
}
countMatching('loot', 'flop')
console.log(matchingLetters)
function countMatching(str1, str2) {
var c = [];
for (var i = 0; i < str1.length; i++) {
if (str2.includes(str1[i]))
if (!c.includes(str1[i])) c.push(str1[i])
}
matchingLetters = c.length;
}
I'm writing on a tab, so there might be mistakes
What I did is that I made c to be a list that contains each character shared between the two strings. And a new character is pushed into c only if the character doesn't exist in it, hence making it a list of unique characters.
Then you can get the length of the list or you can even use the list for other purposes
Related
I'm trying to make program in javascript that makes words of given letters (e.g. given letters: "a,b,c", words: "aaaa", "aaab"... and so on.
const random = (length = 6) => {
// Declare all characters
let chars = 'aąbcćdeęfghijklłmnńoópqrsśtuvwxyzźżAĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ';
// Pick characters randomly
let str = '';
for (let i = 0; i < length; i++) {
str += chars.charAt(i);
}
return str;
};
Is there any way to do it?
Thanks in advance
If what you're looking for is every possible combination of letters, randomness isn't the way to do this.
Try taking a more methodical approach
combinations = []
function allPossibleCombinations(lettersRemaining, lettersSoFar){
if (lettersRemaining.length == 0){
combinations.push(lettersSoFar);
}else{
for (var i = 0; i < lettersRemaining.length; i++){
allPossibleCombinations(lettersSoFar + lettersRemaining.charAt(i), lettersRemaining.slice(0, i) + lettersRemaining.slice(i + 1))
}
}
}
The code is untested, but this general recursive approach should work
I am working on permutation str using recursive, but it can not get out of the for loop.
Can anyone help for this code?
Thank you in advance.
var permutations = [];
var words = [];
function getPerms(str) {
if(str.length == 0) {
permutations.push("");
return permutations;
}
var first = str.charAt(0);//get the first char
var reminder = str.slice(1);//remove the first char
words = getPerms(reminder);
for(var i = 0; i < words.length; i++) {
for(var j = 0; j <= words[i].length; j++) {
var s = insertCharAt(words[i], first, j);
permutations.push(s);
}
}
return permutations;
}
function insertCharAt(word, c, i) {
var start = word.slice(0, i);
var end = word.slice(i);
var result = start + c + end;
return result;
}
console.log(getPerms("abc"));
Your code is fine, except for one issue:
The variables permutations should not be a global variable. You can clearly see this is wrong, by looking at permutations.push(""). This is fine as a temporary result in the deepest level of recursion, but obviously this should not be present in the final result. Yet, because permutations is global, and you never remove anything from it, permutations will keep this "".
The problem gets worse because words gets the permutations reference from the recursive call, and so they point to the very same array! So not only are all previous results iterated, but with an extra character add to them they are pushed again into permutations, which is the same array as words giving you an endless loop: you add to the array you are iterating, and so never get to the end.
The solution is simple:
Make permutations a variable local to the getPerms function. And why not do the same for words when you are at it.
function getPerms(str, depth=0) {
var words = [];
var permutations = [];
if(str.length == 0) {
permutations.push("");
return permutations;
}
var first = str.charAt(0);//get the first char
var reminder = str.slice(1);//remove the first char
words = getPerms(reminder, depth+1);
for(var i = 0; i < words.length; i++) {
for(var j = 0; j <= words[i].length; j++) {
var s = insertCharAt(words[i], first, j);
permutations.push(s);
}
}
return permutations;
}
function insertCharAt(word, c, i) {
var start = word.slice(0, i);
var end = word.slice(i);
var result = start + c + end;
return result;
}
console.log(getPerms("abc"));
Be sure to check these solutions offered for this problem.
The problem is probably at the last call you return permutations and then assign it to words (what you did here is like words = permutation), but this is not an assignement by copy, but by reference (because words and permutations belongs to the same scope + they are array), so from the last call they are the same object (and when the code unstack previous call, they are now the same object). To illustrate, execute the following code. You will see, when you modify words you modify permutations:
var permutations = [];
var words = [];
function getPerms(str) {
if(str.length == 0) {
permutations.push("");
return permutations;
}
var first = str.charAt(0);//get the first char
var reminder = str.slice(1);//remove the first char
words = getPerms(reminder);
words.push("foo");
console.log( permutations);
return permutations;
}
function insertCharAt(word, c, i) {
var start = word.slice(0, i);
var end = word.slice(i);
var result = start + c + end;
return result;
}
console.log(getPerms("abc"));
In your code, you loop on words and modify permutation in the same time (so, based on the previous explanation, it is like modifying words and loop on words in the same time), it is this things which create the infinite loop.
I did not check if your algo works, I am just pointing code's problem.
So I think what you want is:
function getPerms(str) {
var permutations = [];
var words = [];
if(str.length == 0) {
permutations.push("");
return permutations;
}
var first = str.charAt(0);//get the first char
var reminder = str.slice(1);//remove the first char
words = getPerms(reminder);
for(var i = 0; i < words.length; i++) {
for(var j = 0; j <= words[i].length; j++) {
var s = insertCharAt(words[i], first, j);
permutations.push(s);
}
}
return permutations;
}
function insertCharAt(word, c, i) {
var start = word.slice(0, i);
var end = word.slice(i);
var result = start + c + end;
return result;
}
console.log(getPerms("abc"));
Example:
var a = [1,2,3,4,5,6];
I want to display all of the unique 3 number combinations in the array where the sum of those 3 digits is equal to 9 (or n).
So result in this example would be:
[1,2,6]
[2,3,4]
[1,3,5]
Closest thing I could find was permutations of a string...
var alphabet = "abcde"; // shortened to save time
function permute(text) {
if(text.length === 3) { // if length is 3, combination is valid; alert
console.log(text); // or alert
} else {
var newalphabet = alphabet.split("").filter(function(v) {
return text.indexOf(v) === -1;
}); // construct a new alphabet of characters that are not used yet
// because each letter may only occur once in each combination
for(var i = 0; i < newalphabet.length; i++) {
permute(text + newalphabet[i]); // call permute with current text + new
// letter from filtered alphabet
}
}
}
permute("");
This could be a possible solution. Please note it does not take care of unique values and for that you need to add additional logic. However, if the array is sorted and have unique entries then the following will be producing the ideal result.
var a = [1,2,3,4,5,6];
var result = [];
for (var i = 0; i < a.length-2; i++) {
for (var j = i+1; j< a.length-1;j++) {
for (var k = j+1; k < a.length;k++) {
if(a[i]+a[j]+a[k] == 9) {
result.push([a[i],a[j], a[k]]);
}
}
}
}
console.log(result);
This is a challenge for coderbyte I thought I'd try to do it using a different method for solving it than loops, objects. It passed but it isn't perfect. The directions for the challenge are:
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.
function LetterCountI(str){
var wordsAndLetters = {};
var count = 0;
var finalword;
str = str.split(" ");
for(var i = 0; i < str.length; i++){
wordsAndLetters[str[i]] = wordsAndLetters[str[i]] || 0;
}
function countWordLetters(strs){
strs = strs.split("");
var lettercount = {};
for(var i = 0; i <strs.length; i++){
lettercount[strs[i]] = lettercount[strs[i]] || 0;
lettercount[strs[i]]++;
}
return lettercount;
}
for(var words in wordsAndLetters){
wordsAndLetters[words] = countWordLetters(words);
var highestLetterFrequency = wordsAndLetters[words];
for(var values in highestLetterFrequency){
if(highestLetterFrequency[values] > count){
count = highestLetterFrequency[values];
finalword = words;
}
if(count !== 1){
return finalword;
}
}
}
return -1;
}
LetterCountI("today is the greatest day ever!");
Sorry if some of the variable names are confusing I've been up for far too long trying to figure out what I did wrong. If you use the parameters at the bottom of the code it returns 'greatest' like it should however change the parameters to
LetterCountI("toddday is the greatttttest day ever!");
and it logs 'toddday' when it should log 'greatttttest'. Is my code completely wrong? I realize if the parameters were ("caatt dooog") it should log 'caatt' since there are 4 recurring letters but I'm not worried about that I just am concerned about it finding the most recurrence of one letter(but by all means if you have a solution I would like to hear it!). Any changes to the variables if needed to make this code more readable would be appreciated!
The problem with your code is the positioning of the following section of code:
if(count !== 1){
return finalword;
}
Move it from where it currently is to just before the return -1, like so:
for(var words in wordsAndLetters){
wordsAndLetters[words] = countWordLetters(words);
var highestLetterFrequency = wordsAndLetters[words];
for(var values in highestLetterFrequency){
if(highestLetterFrequency[values] > count){
count = highestLetterFrequency[values];
finalword = words;
}
}
}
if(count !== 1){
return finalword;
}
return -1;
The problem with your original code is that your were returning the first word that had repeating characters, which meant your code didn't get far enough to check if any subsequent words had more repeating characters.
Also, just for fun, here is my alternative solution.
Here you go
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
function LetterCountI(str){
var temp = str.split(" ");
var final = '', weight = 0;
for(var i = 0; i < temp.length; ++i) {
var word = temp[i].split("");
if(word.getUnique().length < word.length) {
var diff = word.length - word.getUnique().length;
if(diff > weight){
weight = diff;
final = temp[i];
}
}
}
return final;
}
console.log(LetterCountI("Catt dooog"));
console.log(LetterCountI("toddday is the greatttttest day ever!"));
Viva LinQ !!!!!
var resultPerWord = new Dictionary<string, int>();
var S = "toddday is the greatttttest day ever!";
foreach(var s in S.Split(' '))
{
var theArray =
from w in s
group w by w into g
orderby g.Count() descending
select new { Letter = g.Key, Occurrence = g.Count() };
resultPerWord.Add(s, theArray.First().Occurrence);
}
var r = "-1";
if (resultPerWord.Any(x => x.Value >1))
{
r = resultPerWord.OrderByDescending(x => x.Value).First().Key;
}
i need to find few words or matching pattern using a Javascript.
this is the requirement.
i have a string like this,
Here is a quick guide for the next
time you reach for your favorite oil and some other topics
and i need to match this string against a string like this
favorite oil and some other topics can be based on something blah blah
how do i get the intersection of matching text blocks?
I already tried intersect Javascript script function, for some strings it's not working properly.
How to solve this problem? can this be done using Regex?
Please advice.
You have to find the Longest common substring.
If the strings are not very long, I recommend using Tim's approach. Otherwise, this is a Javascript implementation of the Longest common substring algorithm with dynamic programming. The runtime is O(mn) where m and n are the lengths of the 2 strings respectively.
An example usage:
var first = "Here is a quick guide for the next time you reach for your favorite oil and some other topics";
var second = "favorite oil and some other topics can be based on something blah blah";
console.log(first.intersection(second)); // ["favorite oil and some other topic"]
This is the algorithm implementation. It returns an array of the longest common substring(s). Extended the native String class, so the intersect method is available on all strings.
String.prototype.intersection = function(anotherString) {
var grid = createGrid(this.length, anotherString.length);
var longestSoFar = 0;
var matches = [];
for(var i = 0; i < this.length; i++) {
for(var j = 0; j < anotherString.length; j++) {
if(this.charAt(i) == anotherString.charAt(j)) {
if(i == 0 || j == 0) {
grid[i][j] = 1;
}
else {
grid[i][j] = grid[i-1][j-1] + 1;
}
if(grid[i][j] > longestSoFar) {
longestSoFar = grid[i][j];
matches = [];
}
if(grid[i][j] == longestSoFar) {
var match = this.substring(i - longestSoFar + 1, i);
matches.push(match);
}
}
}
}
return matches;
}
Also need this helper function to create a 2d array with all elements initialize to 0.
// create a 2d array
function createGrid(rows, columns) {
var grid = new Array(rows);
for(var i = 0; i < rows; i++) {
grid[i] = new Array(columns);
for(var j = 0; j < columns; j++) {
grid[i][j] = 0;
}
}
return grid;
}
This isn't very efficient and there are much better ways to do this in general (see #Anurag's answer), but it's simple and works fine for short strings:
function stringIntersection(str1, str2) {
var strTemp;
// Swap parameters if necessary to ensure str1 is the shorter
if (str1.length > str2.length) {
strTemp = str1;
str1 = str2;
str2 = strTemp;
}
// Start with the whole of str1 and try shorter substrings until
// we have a common one
var str1Len = str1.length, l = str1Len, start, substring;
while (l > 0) {
start = str1Len - l;
while (start >= 0) {
substring = str1.slice(start, l);
if (str2.indexOf(substring) > -1) {
return substring;
}
start--;
}
l--;
}
return "";
}
var s1 = "Here is a quick guide for the next time you reach"
+ " for your favorite oil and some other topics";
var s2 = "favorite oil and some other topics can be based on"
+ " something blah blah";
alert( stringIntersection(s1, s2) );
A simple polyfill of filter a string
if (!String.prototype.intersection) {
String.prototype.intersection = function(anotherString, caseInsensitive = false) {
const value = (caseInsensitive) ? this.toLowerCase() : this;
const comp = (caseInsensitive) ? anotherString.toLowerCase() : anotherString;
const ruleArray = comp.split("").reduce((m,v) => {m[v]=true; return m;} ,{})
return this.split("").filter( (c, i) => ruleArray[value[i]] ).join("")
}
}
"HelloWorld".intersection("HEWOLRLLODo", true)
"HelloWorld" - case insensitive
"HelloWorld".intersection("HEWOLRLLODo")
"HoWo" - case sensitive