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
Related
Write a function that accepts a string where letters are grouped together and returns new string with each letter followed by a count of the number of times it appears.
example : ('aeebbccd') should produce // 'a1e2b2c2d1'
function strExpand(str) {
let results = ""
for (let i = 0; i < str.length; i++) {
let charAt = str.charAt(i)
let count = 0
results += charAt
for (let j = 0; j < str.length; j++) {
if (str.charAt(j) === charAt) {
count++;
}
}
results += count;
}
return results;
}
with the input 'aeebbccd' I am getting 'a1e2e2b2b2c2c2d1' instead of 'a1e2b2c2d1'
This function is adding a number after each character, which is the number of times this character appears anywhere in the string. You could instead do it like this to get the result you want.
function strExpand(str) {
let output = "";
// Iterate through each character of the string, appending
// to the output string each time
for (let i = 0; i < str.length; i++) {
let count = 1;
// If the next character is the same, increase the count
// and increment the index in the string
while (str[i + 1] == str[i]) {
count++;
i++;
}
// Add the character and the count to the output string
output += str[i] + count;
}
return output;
}
For sake of completeness,
how about a Regex?
const pattern = /(.)\1*/g; // put a char that exists in a capture group, then see if it repeats directly after
const s = 'aeebbccd';
var result = '';
for (match of s.match(pattern)) {
let this_group = match;
let this_len = match.length;
result = result + this_group[0] + this_len; // get only the first letter from the group
}
console.log(result); // a1e2b2c2d1
This would to the job. edit: hah i see im late :D, but still nice functional way to solve that.
/**
* #param string to count
* #return string $characterA$count. ex. abbccc -> a1b2c3
*/
function toCharacterCountString(str) {
return Array.from(new Set(str).values())
.map(char => {
return `${char}${(str.match(new RegExp(char, "g")) || []).length}`;
}).join('');
}
console.log(toCharacterCountString('abbccc')); // a1b2c3
console.log(toCharacterCountString('aeebbccd')); // a1e2b2c2d1
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
I just started learning JavaScript and I'm extremely annoyed by it.
I want a procedure that decompresses a string of decimal digits like so:
"301051" means "3 zeros, a one, a zero, then 5 ones"
i.e.
"301051"---> "0001011111"
A string of digits of ones and zeros won't be changed at all (and also won't have any more than two consecutive 0's or 1's)
"01001100" ---> "01001100"
I started to work on it, but I'm churning out spaghetti code.
for (i = 0; i < thisString.length;)
{
thisNum = thisString.charCodeAt(i);
if (thisNum > 1)
{
substr = "";
for (j = 0; j < thisNum; j++)
subtr += thisString.charAt(i);
if (i == 0)
thisString = substr + thisString.substring(2
}
}
I don't feel like finishing that because I'm sick of using the limited number of JavaScript string functions. I'm sure the geniuses at Stack Overflow have a 1-line solution for me. Right, guys????
Here's a simple algorithmic solution:
function decompress(str) {
var result = "", char = "";
for (var i = 0; i < str.length; i++) {
char = str.charAt(i);
console.log(char - '0');
if (char > 1) {
result += new Array(+char + 1).join(str.charAt(++i));
} else {
result += char;
}
}
return result;
}
And an even simpler regex solution:
function decompress(str) {
return str.replace(/([2-9])(.)/g, function(m, a, b) {
return new Array(+a + 1).join(b);
});
}
The only magic here is the new Array(+a + 1).join(b) (which is also used by both solutions). The first + turns a (or char) into a number. Then I create an array of a + 1 elements, and join them together with following character as 'glue'. The result is a string of a repetitions of b.
I believe you need something like:
function decompress(thisString) {
var result = '';
for (var i = 0; i < thisString.length; i += 2) {
var thisNum = parseInt(thisString[i], 10);
if (thisNum > 1) {
for (var j = 0; j < thisNum; j++)
result += thisString[i + 1];
} else {
result += (thisString[i] + thisString[i + 1]);
}
}
return result;
}
You have a lot of variables, which are leaking as globals. Make sure you declare each of them using var.
I have been stumped on this problem for a few hours now and am making no progress. I feel like this should be simple. I am trying to Remove duplicate characters in a String without using methods such as Filter or a Reg ex.
Here is my current code:
var duplicate = function(string) {
var newString = string.split("");
var finalArrayWithNoDuplicates = []
for (var i = 0; i < newString.length; i++){
for (var=0; j < newString.length; i++){
while(newString[i])
if (newString[i] !== newString[j]){
}
}
}
return finalArrayWithNoDuplicates.join("");
};
I am able to filter one letter at a time but as I progress down the chain in the while statement I am adding letters that were filtered out originally.
All of the algorithm tutorials for this algorithm are in Java that I have been finding. Is there a way to do this with only using a a for and while loops?
There are several things wrong with the proposed code:
It has serious errors (the inner loop is written all wrong)
You don't need to involve arrays at all, strings will do just fine
The "if char !== other char" check will never provide enough information to act on
Here's an alternative version using for loops and the same basic idea:
function deduplicate(str) {
var result = "";
for (var i = 0; i < str.length; ++i) {
var found = false;
for (var j = 0; j < i; ++j) {
if (str[i] == str[j]) {
found = true;
break;
}
}
if (!found) result += str[i];
}
return result;
}
Each character str[i] in the input string is compared to all characters str[j] that precede it (there is no point in comparing to characters that follow it because we are going to process those when their turn comes up anyway). If the character is not equal to any of those that precede it then we know it's the first of its kind to appear and include it in the result.
Note that this algorithm has O(n²) performance, which is very poor compared to other possible approaches. Its main selling point is that it is straightforward and that everything happens "in front of your eyes".
Here is a slightly modified version of your function that uses an object to keep track of which letters have already been encountered:
var duplicate = function(string) {
var finalArrayWithNoDuplicates = [];
var seen = {};
for (var i = 0; i < string.length; i++) {
if (!seen[string[i]]) {
finalArrayWithNoDuplicates.push(string[i]);
seen[string[i]] = 1;
}
}
return finalArrayWithNoDuplicates.join("");
};
No need for two nested for-loops
No need for "while" loop as well
in the following line of code there are two errors: for (var=0; j < newString.length; i++){ first one is var=0 (compilation error) and second is theat you increment i instead of j
It can be done by adding only unique elements (that don't appear twice) to finalArrayWithNoDuplicates
as follows:
var duplicate = function(newString) {
var finalArrayWithNoDuplicates = []
var x = 0;
for (var i = 0; i < newString.length; i++){
// if the char appears in another index
// or if it's already in the result - don't add it
if (newString.lastIndexOf(newString[i]) !== i || finalArrayWithNoDuplicates.indexOf(newString[i]) > -1){
continue;
}
else{
finalArrayWithNoDuplicates[x++] = newString[i];
}
}
return finalArrayWithNoDuplicates.join("");
};
var arr = [1,2,3,4,5,4,5,6,7];
alert(duplicate(arr));
OUTPUT:
1234567
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