create a unique key from 3 Alphabet - javascript

I'm trying to create a unique key using the alphabets;
I've managed to work it out but I don't really like the approach I took. and I believe someone out there might be able to help me get a better way to do this code. Please let me know if you think of a better idea? or whatever your idea to compare with mine?
I think this might be a good way to share knowledge .. Thanks in advance
let string = 'ABE';
let ar1 = ["A", "B", "C", "D", "E"];
string = string.split('');
if (string[2] !=='E') {
for (let i = 0; i < 5; i++) {
if (string[2] === ar1[i]) {
i = i+1;
string[2] = ar1[i]
}
}
string = string.toString().replace(/,/g, '');
console.log("case 1", string);
} else if (string[1] !=='E' && string[2] ==='E') {
string[2] ='A';
for (let i = 0; i < 5; i++) {
if (string[1] === ar1[i]) {
i = i+1;
let newString = ar1[i];
console.log(ar1[i]);
string[1] = newString;
}
}
string = string.toString().replace(/,/g, '');
console.log("case 2", string);
} else if (string[1] ==='E' && string[2] ==='E') {
string[1] ='A';
string[2] ='A';
for (let i = 0; i < 5; i++) {
if (string[0] === ar1[i]) {
i = i+1;
string[0] = ar1[i];
}
}
string = string.toString().replace(/,/g, '');
console.log("case 3", string);
}
Results would be like:
if string = "AAA" Then the result "AAB"
if string = "AAE" Then result will be "ABA"
if string = "AEE" Then result will be "BAA"

You could encode the value to a numerical value, like this palce value
36 6 1
C B A
2 1 0 78
and encode an incremented value with the wanted characters and length.
function decode(value, characters) {
const
values = Object.fromEntries(Array.from(characters, (v, i) => [v, i]));
return value
.split('')
.reduce((s, v) => s * characters.length + values[v], 0);
}
function encode(value, characters, length = 0) {
let result = '';
do {
result = characters[value % characters.length] + result;
value = Math.floor(value / characters.length);
} while (value);
return result.padStart(length, characters[0]);
}
console.log(decode('AAA', 'ABCDEF')); // 0
console.log(encode(0, 'ABCDEF', 3)); // AAA
console.log(encode(1, 'ABCDEF', 3)); // AAB
console.log(decode('CBA', 'ABCDEF')); // 78
console.log(encode(78, 'ABCDEF', 3)); // CBA
console.log(encode(79, 'ABCDEF', 3)); // CBB

This approach rotates each character by a fixed amount (which could be improved upon), ignoring the other characters.
let ar1 = ["A", "B", "C", "D", "E"];
function scramble(str) {
let rotation=3;
let s = str.split('');
for (let i=0; i<s.length; i++) {
s[i]=ar1[(parseInt(s[i],16)+rotation) % ar1.length];
}
return s.toString().replace(/,/g, '');
}

Related

I'm solving Leetcode problem: 14 using Javascript

I sorted the elements and comparing the first and last string to check the common prefixes. It works for most of the cases, but not for the input ["dog","racecar","car"]. The expected output is "", but what I'm getting is "c" (The "r" in "car" and "r" in "racecar"). I can tell the code to remove the last char, but this will break the other cases such as ["car", "car", "car"]. Not sure what am I missing. Any insights would help me improve.
Thanks
var longestCommonPrefix = function(strs) {
let count=0
const sortedString = strs.sort()
const firstString = sortedString[0]
const lastString = sortedString[sortedString.length-1]
for(let i=0; i< firstString.length; i++) {
if(firstString.charAt(i) === lastString.charAt(i)) {
count++
}
}
console.log(firstString.substring(0, count))
};
longestCommonPrefix(
["dog","racecar","car"])
You need to break out of the loop as soon as a match is not found. Otherwise, for example, ra and ca match on the second index, the a - which is undesirable.
var longestCommonPrefix = function(strs) {
let count = 0
const sortedString = strs.sort()
const firstString = sortedString[0]
const lastString = sortedString[sortedString.length - 1]
for (let i = 0; i < firstString.length; i++) {
if (firstString.charAt(i) === lastString.charAt(i)) {
count++
} else {
break;
}
}
console.log(firstString.substring(0, count))
};
longestCommonPrefix(
["dog", "racecar", "car"])
or, refactored a bit
const longestCommonPrefix = (strs) => {
strs.sort();
const firstString = strs[0];
const lastString = strs[strs.length - 1];
let prefixSoFar = '';
for (let i = 0; i < firstString.length; i++) {
if (firstString[i] === lastString[i]) {
prefixSoFar += firstString[i];
} else {
return prefixSoFar;
}
}
return prefixSoFar;
};
console.log(longestCommonPrefix(["dog", "racecar", "car"]));

Creating various arrays from a string using LOOPS

I have a string of values
"000111111122222223333333444455556666"
How could I use a loop to produce one array for index values from 0 to 3 (create an array of [000] and then another array of index values from 3 to 10, 10 to 17, 17 to 24, producing eg. [1111111, 2222222, 333333] and then another loop to produce an array of index values from 24 to 28, 28 to 32, 32 to 36, producing eg. [4444, 5555, 6666])?
So in total 3 different arrays have been created using three different for loops.
array1 = [000]
array2 = [1111111, 2222222, 333333]
array3 = [4444, 5555, 6666]
You may wish to try something line this (only a schematic solution!):
var l_Input = "000111111122222223333333444455556666" ;
var l_Array_1 = [] ;
var l_Array_2 = [] ;
var l_Array_3 = [] ;
var l_One_Char ;
for (var i = 0 ; i < l_Input.length ; i++) {
l_One_Char = l_Input.substring(i,i) ;
if (i < 3) {
l_Array_1.push(l_One_Char) ;
continue ;
}
if (i >= 3 && i < 10) {
l_Array_2.push(l_One_Char) ;
continue ;
}
:
:
}
I think this would work.
const str = '000111111122222223333333444455556666';
function makeArr(str, item) {
let firstIndex = str.indexOf(item);
let lastIndex = str.lastIndexOf(item) + 1;
return [ str.substring(firstIndex, lastIndex) ];
}
const first = makeArr(str, 0);
const second = [].concat(makeArr(str, 1))
.concat(makeArr(str, 2))
.concat(makeArr(str, 3));
const third = [].concat(makeArr(str, 4))
.concat(makeArr(str, 3))
.concat(makeArr(str, 3));
You could map the sub strings.
var str = '000111111122222223333333444455556666',
parts = [[3], [7, 7, 7], [4, 4, 4]],
result = parts.map((i => a => a.map(l => str.slice(i, i += l)))(0));
console.log(result);
function split(string, start, end) {
var result = [],
substring = string[start],
split;
for (var i = start + 1; i < end; i++) {
var char = string[i];
if (char === substring[0])
substring += char;
else {
result.push(substring);
substring = char;
}
}
result.push(substring);
return result;
}
split("00011122",0,8)
["000", "111", "22"]
To do this dynamically, you can use .split() and .map() methods to make an array from your string then group this array items by value.
This is how should be our code:
const str = "000111111122222223333333444455556666";
var groupArrayByValues = function(arr) {
return arr.reduce(function(a, x) {
(a[x] = a[x] || []).push(x);
return a;
}, []);
};
var arr = str.split("").map(v => +v);
var result = groupArrayByValues(arr);
This will give you an array of separate arrays with similar values each.
Demo:
const str = "000111111122222223333333444455556666";
var groupArrayByValues = function(arr) {
return arr.reduce(function(a, x) {
(a[x] = a[x] || []).push(x);
return a;
}, []);
};
var arr = str.split("").map(v => +v);
var result = groupArrayByValues(arr);
console.log(result);

Alibaba interview: print a sentence with min spaces

I saw this interview question and gave a go. I got stuck. The interview question is:
Given a string
var s = "ilikealibaba";
and a dictionary
var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
try to give the s with min space
The output may be
i like alibaba (2 spaces)
i like ali baba (3 spaces)
but pick no.1
I have some code, but got stuck in the printing.
If you have better way to do this question, let me know.
function isStartSub(part, s) {
var condi = s.startsWith(part);
return condi;
}
function getRestStr(part, s) {
var len = part.length;
var len1 = s.length;
var out = s.substring(len, len1);
return out;
}
function recPrint(arr) {
if(arr.length == 0) {
return '';
} else {
var str = arr.pop();
return str + recPrint(arr);
}
}
// NOTE: have trouble to print
// Or if you have better ways to do this interview question, please let me know
function myPrint(arr) {
return recPrint(arr);
}
function getMinArr(arr) {
var min = Number.MAX_SAFE_INTEGER;
var index = 0;
for(var i=0; i<arr.length; i++) {
var sub = arr[i];
if(sub.length < min) {
min = sub.length;
index = i;
} else {
}
}
return arr[index];
}
function rec(s, d, buf) {
// Base
if(s.length == 0) {
return;
} else {
}
for(var i=0; i<d.length; i++) {
var subBuf = [];
// baba
var part = d[i];
var condi = isStartSub(part, s);
if(condi) {
// rest string
var restStr = getRestStr(part, s);
rec(restStr, d, subBuf);
subBuf.unshift(part);
buf.unshift(subBuf);
} else {
}
} // end loop
}
function myfunc(s, d) {
var buf = [];
rec(s, d, buf);
console.log('-- test --');
console.dir(buf, {depth:null});
return myPrint(buf);
}
// Output will be
// 1. i like alibaba (with 2 spaces)
// 2. i like ali baba (with 3 spaces)
// we pick no.1, as it needs less spaces
var s = "ilikealibaba";
var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
var out = myfunc(s, d);
console.log(out);
Basically, my output is, not sure how to print it....
[ [ 'i', [ 'like', [ 'alibaba' ], [ 'ali', [ 'baba' ] ] ] ] ]
This problem is best suited for a dynamic programming approach. The subproblem is, "what is the best way to create a prefix of s". Then, for a given prefix of s, we consider all words that match the end of the prefix, and choose the best one using the results from the earlier prefixes.
Here is an implementation:
var s = "ilikealibaba";
var arr = ["i", "like", "ali", "liba", "baba", "alibaba"];
var dp = []; // dp[i] is the optimal solution for s.substring(0, i)
dp.push("");
for (var i = 1; i <= s.length; i++) {
var best = null; // the best way so far for s.substring(0, i)
for (var j = 0; j < arr.length; j++) {
var word = arr[j];
// consider all words that appear at the end of the prefix
if (!s.substring(0, i).endsWith(word))
continue;
if (word.length == i) {
best = word; // using single word is optimal
break;
}
var prev = dp[i - word.length];
if (prev === null)
continue; // s.substring(i - word.length) can't be made at all
if (best === null || prev.length + word.length + 1 < best.length)
best = prev + " " + word;
}
dp.push(best);
}
console.log(dp[s.length]);
pkpnd's answer is along the right track. But word dictionaries tend to be quite large sets, and iterating over the entire dictionary at every character of the string is going to be inefficient. (Also, saving the entire sequence for each dp cell may consume a large amount of space.) Rather, we can frame the question, as we iterate over the string, as: given all the previous indexes of the string that had dictionary matches extending back (either to the start or to another match), which one is both a dictionary match when we include the current character, and has a smaller length in total. Generally:
f(i) = min(
f(j) + length(i - j) + (1 if j is after the start of the string)
)
for all j < i, where string[j] ended a dictionary match
and string[j+1..i] is in the dictionary
Since we only add another j when there is a match and a new match can only extend back to a previous match or to the start of the string, our data structure could be an array of tuples, (best index this match extends back to, total length up to here). We add another tuple if the current character can extend a dictionary match back to another record we already have. We can also optimize by exiting early from the backwards search once the matched substring would be greater than the longest word in the dictionary, and building the substring to compare against the dictionary as we iterate backwards.
JavaScript code:
function f(str, dict){
let m = [[-1, -1, -1]];
for (let i=0; i<str.length; i++){
let best = [null, null, Infinity];
let substr = '';
let _i = i;
for (let j=m.length-1; j>=0; j--){
let [idx, _j, _total] = m[j];
substr = str.substr(idx + 1, _i - idx) + substr;
_i = idx;
if (dict.has(substr)){
let total = _total + 1 + i - idx;
if (total < best[2])
best = [i, j, total];
}
}
if (best[0] !== null)
m.push(best);
}
return m;
}
var s = "ilikealibaba";
var d = new Set(["i", "like", "ali", "liba", "baba", "alibaba"]);
console.log(JSON.stringify(f(s,d)));
We can track back our result:
[[-1,-1,-1],[0,0,1],[4,1,6],[7,2,10],[11,2,14]]
[11, 2, 14] means a total length of 14,
where the previous index in m is 2 and the right index
of the substr is 11
=> follow it back to m[2] = [4, 1, 6]
this substr ended at index 4 (which means the
first was "alibaba"), and followed m[1]
=> [0, 0, 1], means this substr ended at index 1
so the previous one was "like"
And there you have it: "i like alibaba"
As you're asked to find a shortest answer probably Breadth-First Search would be a possible solution. Or you could look into A* Search.
Here is working example with A* (cause it's less bring to do than BFS :)), basically just copied from Wikipedia article. All the "turning string into a graph" magick happens in the getNeighbors function
https://jsfiddle.net/yLeps4v5/4/
var str = 'ilikealibaba'
var dictionary = ['i', 'like', 'ali', 'baba', 'alibaba']
var START = -1
var FINISH = str.length - 1
// Returns all the positions in the string that we can "jump" to from position i
function getNeighbors(i) {
const matchingWords = dictionary.filter(word => str.slice(i + 1, i + 1 + word.length) == word)
return matchingWords.map(word => i + word.length)
}
function aStar(start, goal) {
// The set of nodes already evaluated
const closedSet = {};
// The set of currently discovered nodes that are not evaluated yet.
// Initially, only the start node is known.
const openSet = [start];
// For each node, which node it can most efficiently be reached from.
// If a node can be reached from many nodes, cameFrom will eventually contain the
// most efficient previous step.
var cameFrom = {};
// For each node, the cost of getting from the start node to that node.
const gScore = dictionary.reduce((acc, word) => { acc[word] = Infinity; return acc }, {})
// The cost of going from start to start is zero.
gScore[start] = 0
while (openSet.length > 0) {
var current = openSet.shift()
if (current == goal) {
return reconstruct_path(cameFrom, current)
}
closedSet[current] = true;
getNeighbors(current).forEach(neighbor => {
if (closedSet[neighbor]) {
return // Ignore the neighbor which is already evaluated.
}
if (openSet.indexOf(neighbor) == -1) { // Discover a new node
openSet.push(neighbor)
}
// The distance from start to a neighbor
var tentative_gScore = gScore[current] + 1
if (tentative_gScore >= gScore[neighbor]) {
return // This is not a better path.
}
// This path is the best until now. Record it!
cameFrom[neighbor] = current
gScore[neighbor] = tentative_gScore
})
}
throw new Error('path not found')
}
function reconstruct_path(cameFrom, current) {
var answer = [];
while (cameFrom[current] || cameFrom[current] == 0) {
answer.push(str.slice(cameFrom[current] + 1, current + 1))
current = cameFrom[current];
}
return answer.reverse()
}
console.log(aStar(START, FINISH));
You could collect all possible combinations of the string by checking the starting string and render then the result.
If more than one result has the minimum length, all results are taken.
It might not work for extrema with string who just contains the same base string, like 'abcabc' and 'abc'. In this case I suggest to use the shortest string and update any part result by iterating for finding longer strings and replace if possible.
function getWords(string, array = []) {
words
.filter(w => string.startsWith(w))
.forEach(s => {
var rest = string.slice(s.length),
temp = array.concat(s);
if (rest) {
getWords(rest, temp);
} else {
result.push(temp);
}
});
}
var string = "ilikealibaba",
words = ["i", "like", "ali", "liba", "baba", "alibaba"],
result = [];
getWords(string);
console.log('all possible combinations:', result);
console.log('result:', result.reduce((r, a) => {
if (!r || r[0].length > a.length) {
return [a];
}
if (r[0].length === a.length) {
r.push(a);
}
return r;
}, undefined))
Use trie data structure
Construct a trie data structure based on the dictionary data
Search the sentence for all possible slices and build a solution tree
Deep traverse the solution tree and sort the final combinations
const sentence = 'ilikealibaba';
const words = ['i', 'like', 'ali', 'liba', 'baba', 'alibaba',];
class TrieNode {
constructor() { }
set(a) {
this[a] = this[a] || new TrieNode();
return this[a];
}
search(word, marks, depth = 1) {
word = Array.isArray(word) ? word : word.split('');
const a = word.shift();
if (this[a]) {
if (this[a]._) {
marks.push(depth);
}
this[a].search(word, marks, depth + 1);
} else {
return 0;
}
}
}
TrieNode.createTree = words => {
const root = new TrieNode();
words.forEach(word => {
let currentNode = root;
for (let i = 0; i < word.length; i++) {
currentNode = currentNode.set(word[i]);
}
currentNode.set('_');
});
return root;
};
const t = TrieNode.createTree(words);
function searchSentence(sentence) {
const marks = [];
t.search(sentence, marks);
const ret = {};
marks.map(mark => {
ret[mark] = searchSentence(sentence.slice(mark));
});
return ret;
}
const solutionTree = searchSentence(sentence);
function deepTraverse(tree, sentence, targetLen = sentence.length) {
const stack = [];
const sum = () => stack.reduce((acc, mark) => acc + mark, 0);
const ret = [];
(function traverse(tree) {
const keys = Object.keys(tree);
keys.forEach(key => {
stack.push(+key);
if (sum() === targetLen) {
const result = [];
let tempStr = sentence;
stack.forEach(mark => {
result.push(tempStr.slice(0, mark));
tempStr = tempStr.slice(mark);
});
ret.push(result);
}
if(tree[key]) {
traverse(tree[key]);
}
stack.pop();
});
})(tree);
return ret;
}
const solutions = deepTraverse(solutionTree, sentence);
solutions.sort((s1, s2) => s1.length - s2.length).forEach((s, i) => {
console.log(`${i + 1}. ${s.join(' ')} (${s.length - 1} spaces)`);
});
console.log('pick no.1');

Find all sentence permutations with synonymous words? [duplicate]

This question already has answers here:
Cartesian product of multiple arrays in JavaScript
(35 answers)
Closed 1 year ago.
I'm having trouble coming up with code to generate combinations from n number of arrays with m number of elements in them, in JavaScript. I've seen similar questions about this for other languages, but the answers incorporate syntactic or library magic that I'm unsure how to translate.
Consider this data:
[[0,1], [0,1,2,3], [0,1,2]]
3 arrays, with a different number of elements in them. What I want to do is get all combinations by combining an item from each array.
For example:
0,0,0 // item 0 from array 0, item 0 from array 1, item 0 from array 2
0,0,1
0,0,2
0,1,0
0,1,1
0,1,2
0,2,0
0,2,1
0,2,2
And so on.
If the number of arrays were fixed, it would be easy to make a hard coded implementation. But the number of arrays may vary:
[[0,1], [0,1]]
[[0,1,3,4], [0,1], [0], [0,1]]
Any help would be much appreciated.
Here is a quite simple and short one using a recursive helper function:
function cartesian(...args) {
var r = [], max = args.length-1;
function helper(arr, i) {
for (var j=0, l=args[i].length; j<l; j++) {
var a = arr.slice(0); // clone arr
a.push(args[i][j]);
if (i==max)
r.push(a);
else
helper(a, i+1);
}
}
helper([], 0);
return r;
}
Usage:
cartesian([0,1], [0,1,2,3], [0,1,2]);
To make the function take an array of arrays, just change the signature to function cartesian(args) instead of using rest parameter syntax.
I suggest a simple recursive generator function:
// JS
function* cartesianIterator(head, ...tail) {
const remainder = tail.length ? cartesianIterator(...tail) : [[]];
for (let r of remainder) for (let h of head) yield [h, ...r];
}
// get values:
const cartesian = items => [...cartesianIterator(items)];
console.log(cartesian(input));
// TS
function* cartesianIterator<T>(items: T[][]): Generator<T[]> {
const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]];
for (let r of remainder) for (let h of items.at(0)!) yield [h, ...r];
}
// get values:
const cartesian = <T>(items: T[][]) => [...cartesianIterator(items)];
console.log(cartesian(input));
You could take an iterative approach by building sub arrays.
var parts = [[0, 1], [0, 1, 2, 3], [0, 1, 2]],
result = parts.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
console.log(result.map(a => a.join(', ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
After doing a little research I discovered a previous related question:
Finding All Combinations of JavaScript array values
I've adapted some of the code from there so that it returns an array of arrays containing all of the permutations:
function(arraysToCombine) {
var divisors = [];
for (var i = arraysToCombine.length - 1; i >= 0; i--) {
divisors[i] = divisors[i + 1] ? divisors[i + 1] * arraysToCombine[i + 1].length : 1;
}
function getPermutation(n, arraysToCombine) {
var result = [],
curArray;
for (var i = 0; i < arraysToCombine.length; i++) {
curArray = arraysToCombine[i];
result.push(curArray[Math.floor(n / divisors[i]) % curArray.length]);
}
return result;
}
var numPerms = arraysToCombine[0].length;
for(var i = 1; i < arraysToCombine.length; i++) {
numPerms *= arraysToCombine[i].length;
}
var combinations = [];
for(var i = 0; i < numPerms; i++) {
combinations.push(getPermutation(i, arraysToCombine));
}
return combinations;
}
I've put a working copy at http://jsfiddle.net/7EakX/ that takes the array you gave earlier ([[0,1], [0,1,2,3], [0,1,2]]) and outputs the result to the browser console.
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
console.log(charSet.reduce((a,b)=>a.flatMap(x=>b.map(y=>x+y)),['']))
Just for fun, here's a more functional variant of the solution in my first answer:
function cartesian() {
var r = [], args = Array.from(arguments);
args.reduceRight(function(cont, factor, i) {
return function(arr) {
for (var j=0, l=factor.length; j<l; j++) {
var a = arr.slice(); // clone arr
a[i] = factor[j];
cont(a);
}
};
}, Array.prototype.push.bind(r))(new Array(args.length));
return r;
}
Alternative, for full speed we can dynamically compile our own loops:
function cartesian() {
return (cartesian.cache[arguments.length] || cartesian.compile(arguments.length)).apply(null, arguments);
}
cartesian.cache = [];
cartesian.compile = function compile(n) {
var args = [],
indent = "",
up = "",
down = "";
for (var i=0; i<n; i++) {
var arr = "$"+String.fromCharCode(97+i),
ind = String.fromCharCode(105+i);
args.push(arr);
up += indent+"for (var "+ind+"=0, l"+arr+"="+arr+".length; "+ind+"<l"+arr+"; "+ind+"++) {\n";
down = indent+"}\n"+down;
indent += " ";
up += indent+"arr["+i+"] = "+arr+"["+ind+"];\n";
}
var body = "var res=[],\n arr=[];\n"+up+indent+"res.push(arr.slice());\n"+down+"return res;";
return cartesian.cache[n] = new Function(args, body);
}
var f = function(arr){
if(typeof arr !== 'object'){
return false;
}
arr = arr.filter(function(elem){ return (elem !== null); }); // remove empty elements - make sure length is correct
var len = arr.length;
var nextPerm = function(){ // increase the counter(s)
var i = 0;
while(i < len)
{
arr[i].counter++;
if(arr[i].counter >= arr[i].length){
arr[i].counter = 0;
i++;
}else{
return false;
}
}
return true;
};
var getPerm = function(){ // get the current permutation
var perm_arr = [];
for(var i = 0; i < len; i++)
{
perm_arr.push(arr[i][arr[i].counter]);
}
return perm_arr;
};
var new_arr = [];
for(var i = 0; i < len; i++) // set up a counter property inside the arrays
{
arr[i].counter = 0;
}
while(true)
{
new_arr.push(getPerm()); // add current permutation to the new array
if(nextPerm() === true){ // get next permutation, if returns true, we got them all
break;
}
}
return new_arr;
};
Here's another way of doing it. I treat the indices of all of the arrays like a number whose digits are all different bases (like time and dates), using the length of the array as the radix.
So, using your first set of data, the first digit is base 2, the second is base 4, and the third is base 3. The counter starts 000, then goes 001, 002, then 010. The digits correspond to indices in the arrays, and since order is preserved, this is no problem.
I have a fiddle with it working here: http://jsfiddle.net/Rykus0/DS9Ea/1/
and here is the code:
// Arbitrary base x number class
var BaseX = function(initRadix){
this.radix = initRadix ? initRadix : 1;
this.value = 0;
this.increment = function(){
return( (this.value = (this.value + 1) % this.radix) === 0);
}
}
function combinations(input){
var output = [], // Array containing the resulting combinations
counters = [], // Array of counters corresponding to our input arrays
remainder = false, // Did adding one cause the previous digit to rollover?
temp; // Holds one combination to be pushed into the output array
// Initialize the counters
for( var i = input.length-1; i >= 0; i-- ){
counters.unshift(new BaseX(input[i].length));
}
// Get all possible combinations
// Loop through until the first counter rolls over
while( !remainder ){
temp = []; // Reset the temporary value collection array
remainder = true; // Always increment the last array counter
// Process each of the arrays
for( i = input.length-1; i >= 0; i-- ){
temp.unshift(input[i][counters[i].value]); // Add this array's value to the result
// If the counter to the right rolled over, increment this one.
if( remainder ){
remainder = counters[i].increment();
}
}
output.push(temp); // Collect the results.
}
return output;
}
// Input is an array of arrays
console.log(combinations([[0,1], [0,1,2,3], [0,1,2]]));
You can use a recursive function to get all combinations
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
let loopOver = (arr, str = '', final = []) => {
if (arr.length > 1) {
arr[0].forEach(v => loopOver(arr.slice(1), str + v, final))
} else {
arr[0].forEach(v => final.push(str + v))
}
return final
}
console.log(loopOver(charSet))
This code can still be shorten using ternary but i prefer the first version for readability 😊
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
let loopOver = (arr, str = '') => arr[0].map(v => arr.length > 1 ? loopOver(arr.slice(1), str + v) : str + v).flat()
console.log(loopOver(charSet))
Another implementation with ES6 recursive style
Array.prototype.cartesian = function(a,...as){
return a ? this.reduce((p,c) => (p.push(...a.cartesian(...as).map(e => as.length ? [c,...e] : [c,e])),p),[])
: this;
};
console.log(JSON.stringify([0,1].cartesian([0,1,2,3], [[0],[1],[2]])));

Counting number of vowels in a string with JavaScript

I'm using basic JavaScript to count the number of vowels in a string. The below code works but I would like to have it cleaned up a bit. Would using .includes() help at all considering it is a string? I would like to use something like string.includes("a", "e", "i", "o", "u") if at all possible to clean up the conditional statement. Also, is it needed to convert the input into a string?
function getVowels(str) {
var vowelsCount = 0;
//turn the input into a string
var string = str.toString();
//loop through the string
for (var i = 0; i <= string.length - 1; i++) {
//if a vowel, add to vowel count
if (string.charAt(i) == "a" || string.charAt(i) == "e" || string.charAt(i) == "i" || string.charAt(i) == "o" || string.charAt(i) == "u") {
vowelsCount += 1;
}
}
return vowelsCount;
}
You can actually do this with a small regex:
function getVowels(str) {
var m = str.match(/[aeiou]/gi);
return m === null ? 0 : m.length;
}
This just matches against the regex (g makes it search the whole string, i makes it case-insensitive) and returns the number of matches. We check for null incase there are no matches (ie no vowels), and return 0 in that case.
Convert the string to an array using the Array.from() method, then use the Array.prototype.filter() method to filter the array to contain only vowels, and then the length property will contain the number of vowels.
const countVowels = str => Array.from(str)
.filter(letter => 'aeiou'.includes(letter)).length;
console.log(countVowels('abcdefghijklmnopqrstuvwxyz')); // 5
console.log(countVowels('test')); // 1
console.log(countVowels('ddd')); // 0
function countVowels(subject) {
return subject.match(/[aeiou]/gi).length;
}
You don't need to convert anything, Javascript's error handling is enough to hint you on such a simple function if it will be needed.
Short and ES6, you can use the function count(str);
const count = str => (str.match(/[aeiou]/gi) || []).length;
This could also be solved using .replace() method by replacing anything that isn't a vowel with an empty string (basically it will delete those characters) and returning the new string length:
function vowelCount(str) {
return str.replace(/[^aeiou]/gi, "").length;
};
or if you prefer ES6
const vowelCount = (str) => ( str.replace(/[^aeiou]/gi,"").length )
You can convert the given string into an array using the spread operator, and then you can filter() the characters to only those which are vowels (case-insensitive).
Afterwards, you can check the length of the array to obtain the total number of vowels in the string:
const vowel_count = string => [...string].filter(c => 'aeiou'.includes(c.toLowerCase())).length;
console.log(vowel_count('aaaa')); // 4
console.log(vowel_count('AAAA')); // 4
console.log(vowel_count('foo BAR baz QUX')); // 5
console.log(vowel_count('Hello, world!')); // 3
You can use the simple includes function, which returns true if the given array contains the given character, and false if not.
Note: The includes() method is case sensitive. So before comparing a character convert it to lowercase to avoid missing all the possible cases.
for (var i = 0; i <= string.length - 1; i++) {
if ('aeiou'.includes(string[i].toLowerCase())) {
vowelsCount += 1;
}
}
Use this function to get the count of vowels within a string. Works pretty well.
function getVowelsCount(str)
{
//splits the vowels string into an array => ['a','e','i','o','u','A'...]
let arr_vowel_list = 'aeiouAEIOU'.split('');
let count = 0;
/*for each of the elements of the splitted string(i.e. str), the vowels list would check
for any occurence and increments the count, if present*/
str.split('').forEach(function(e){
if(arr_vowel_list.indexOf(e) !== -1){
count++;} });
//and now log this count
console.log(count);}
//Function Call
getVowelsCount("World Of Programming");
Output for the given string would be 5. Try this out.
//Code -
function getVowelsCount(str)
{
let arr_vowel_list = 'aeiouAEIOU'.split('');
let count = 0;
str.split('').forEach(function(e){
if(arr_vowel_list.indexOf(e) !== -1){
count++;} });
console.log(count);
}
Use match but be careful as it can return a null if no match is found. This solves it:
const countVowels = (subject => (subject.match(/[aeiou]/gi) || []).length);
function vowels(str) {
let count=0;
const checker=['a','e','i','o','u'];
for (let char of str.toLowerCase){
if (checker.includes(char)) {
count++;
}
return count;
}
function vowels(str) {
const match = str.match(/[aeiou]/gi);
return match ? match.length : 0 ;
}
count = function(a) {
//var a=document.getElementById("t");
console.log(a); //to see input string on console
n = a.length;
console.log(n); //calculated length of string
var c = 0;
for (i = 0; i < n; i++) {
if ((a[i] == "a") || (a[i] == "e") || (a[i] == "i") || (a[i] == "o") || (a[i] == "u")) {
console.log(a[i]); //just to verify
c += 1;
}
}
document.getElementById("p").innerText = c;
}
<p>count of vowels </p>
<p id="p"></p>
<input id="t" />
<input type="button" value="count" onclick="count(t.value)" />
This is the shortest solution
function getCount(str) {
return (str.match(/[aeiou]/ig)||[]).length;
}
const containVowels = str => {
const helper = ['a', 'e', 'i', 'o', 'u'];
const hash = {};
for (let c of str) {
if (helper.indexOf(c) !== -1) {
if (hash[c]) {
hash[c]++;
} else {
hash[c] = 1;
}
}
}
let count = 0;
for (let k in hash) {
count += hash[k];
}
return count;
};
console.log(containVowels('aaaa'));
As the introduction of forEach in ES5 this could be achieved in a functional approach, in a more compact way, and also have the count for each vowel and store that count in an Object.
function vowelCount(str){
let splitString=str.split('');
let obj={};
let vowels="aeiou";
splitString.forEach((letter)=>{
if(vowels.indexOf(letter.toLowerCase())!==-1){
if(letter in obj){
obj[letter]++;
}else{
obj[letter]=1;
}
}
});
return obj;
}
My solution:
const str = "In West Philadephia, born and raised.";
const words = str.split("");
function getVowelCount() {
return words.filter(word => word.match(/[aeiou]/gi)).length;
}
console.log(getVowelCount());
Output: 12
You can easily solve this using simple regex. match() method matches string agains a regex variable. return an array if the is a matches and return null if no match is found.
function getVowels(str) {
let vowelsCount = 0;
const regex = /[aiueo]/gi;
vowelsCount = str.match(regex);
return vowelsCount ? vowelsCount.length : 0;
}
console.log(getVowels('Hello World')) => return 3
console.log(getVoewls('bbbcccddd') => return 0
Just use this function [for ES5] :
function countVowels(str){
return (str.match(/[aeiou]/gi) == null) ? 0 : str.match(/[aeiou]/gi).length;
}
Will work like a charm
(A)
const countVowels = data => [...data.toLowerCase()].filter(char => 'aeiou'.includes(char)).length;
(B)
const countVowels = data => data.toLowerCase().split('').filter(char => 'aeiou'.includes(char)).length;
countVowels("Stackoverflow") // 4
The following works and is short:
function countVowels(str) {
return ( str = str.match(/[aeiou]/gi)) ? str.length : 0;
}
console.log(countVowels("abracadabra")); // 5
console.log(countVowels("")); // 0
One more method (using reduce):
function getVowels(str) {
return Array.from(str).reduce((count, letter) => count + 'aeiou'.includes(letter), 0);
}
Here is the my solution for the problem:
function getVowelsCount(s) {
let vowels = ["a", "e", "i", "o", "u"];
let count=0;
for(let v of s) {
if(vowels.includes(v)){
console.log(v);
count=count+1;
}
}
console.log(count);
}
After research and without using regex, this is what I found the simplest to understand for new devs like me.
function vowelCount (string) {
let vowel = "aeiouy"; // can also be array
let result = 0;
for (let i = 0; i < string.length; i++) {
if (vowel.includes(string[i].toLowerCase())) {
result++;
}
}
return result;
}
console.log(vowelCount("cAkeYE"));
function vowelCount(str){
str=str.toLowerCase()
let count=[]
for(let i=0;i<str.length;i++){
if(str.charAt(i)=='u'||str.charAt(i)=='o'||str.charAt(i)=='i'||str.charAt(i)=='e'||str.charAt(i)=='a'){
count.push(str.charAt(i))//to store all the vowels in an array
}
}
let eachcount={}
count.forEach((x)=>eachcount[x]?eachcount[x]++:eachcount[x]=1) //to count each vowel from the count array
return eachcount
}
console.log(vowelCount("hello how Are You"))
function vowelsCount(sentence) {
let vowels = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"];
let count = 0;
let letters = Array.from(sentence);
letters.forEach(function (value) {
if (vowels.includes(value)) {
count++
}
})
return count;
}
console.log(vowelsCount("StackOverFlow"));
Another solution using Set to lookup characters in constant time and reduce() to do the actual counting. The implementation also uses the spread syntax for string as strings are Iterable.
/**
* Count vowels in a string. Ignores case.
* #param {string} str String to count the vowels in
* #returns numbers of vowels
*/
function countVowels(str) {
let vowels = new Set("aeiou")
return [...str.toLowerCase()].reduce((count, character) => count + vowels.has(character) || 0, 0)
};
console.log(countVowels("apple"))
console.log(countVowels("pears are yummy"))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources