Reputation: 171
I am trying to create a function that looks to see if any of the characters in an array are in a string, and if so, how many.
I have tried to calculate every pattern, but there is too much. I tried using the alternative to the "in" operator from Python, but that didn't work out as well
function calc_fit(element) {
var fitness_let = ["e", "l", "m", "n", "t"]
}
}
The element
is the string, and the fitness_let array is the array of things that I need to check to see if they are in the string, and if so, how many.
Upvotes: 16
Views: 1102
Reputation: 15464
You can count occurrences with an identical value of an array using map and filter:
let str="I love JavaScript and Node.js ";
let arr=str.replace(/[^a-zA-Z]/g, '').split('');
const mapped = [...new Set(arr)].map(a => `${a} occurs ${arr.filter(a1 => a1 === a).length } time(s)`);
console.log(mapped);
Upvotes: 11
Reputation: 7436
Here is a slightly different approach relying on function generators.
There is no relevant reason for using this over other solutions, but it allows to give additional control on the whole cycle.
As a side note, the string is iterated only once, so the whole "iteration" cycle should be quite fast.
Explanation is directly in the code below.
The output is an object where each key is a char and holds the amount of occurrences, holding all the searched needles.
If the array of searched characters is not passed, it is automatically built inside the calc_fit function, this will return both uppercase and lowercase occurrences separately, including punctuation and symbols. This is easily customizable though.
// Iterates a string and yield the current looped char if it exists in the chars list.
function* matchChars(s, chars) {
for (var char of s) {
if (chars.indexOf(char) > -1) yield { char: char };
}
}
// not sure why the function was named in this way in the original code, but hey, it's the OP's function name.
function calc_fit(element, chars) {
chars = chars || [...new Set(element)];
// builds an object from the above array, where the structure has the key which is the char, and the value which is initially 0.
const matchList = chars.reduce((acc,next) => (acc[next] = 0, acc), {});
// Iterates all the matches. For each match, it increments the amount of matches of matchList.
for (var match of matchChars(element, chars)) matchList[match.char]++;
// finally, returns matchList.
return matchList;
}
// assertions: should match all the characters.
console.log(calc_fit('element', ["e", "l", "m", "n", "t"]));
// assertions: should return all zeros.
console.log(calc_fit('', ["e", "l", "m", "n", "t"]));
// assertions: should automatically detect chars, even upper case and lower case.
console.log(calc_fit('hello, world. ThIs is beatiful!'));
Upvotes: 0
Reputation: 17190
First, and to generalize the method, it will be better if calc_fit()
takes the array of letters as an argument too. Then, you can create a Map from the array with the counter of each letter starting on 0
. Finally, you traverse the string and increment the respective counter of each letter when needed.
function calc_fit(element, fitness_let)
{
// Create a Map from the array of letters to search.
let map = new Map(fitness_let.map(l => ([l, 0])));
// Traverse the string and increment counter of letters.
for (const c of element)
{
if (map.has(c))
map.set(c, map.get(c) + 1);
}
return map;
}
let res = calc_fit("This is a string with some letters", ["e","l","m","n","t"]);
res.forEach((counter, letter) => console.log(`${letter} => ${counter}`));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Upvotes: 3
Reputation: 12900
You could create a hash map and leverage reduce to count all instances found
Example:
const counts = {};
["e", "l", "m", "n", "t"].forEach( e => counts[e] = 0 );
const letters = "hey look! a string!".split("");
const results = letters.reduce( (acc, curr) => {
if (acc.hasOwnProperty(curr)) { acc[curr] += 1; }
return acc;
}, counts);
console.log(results);
Upvotes: 0
Reputation: 37755
If you want to get no. of times each character appeared than you can use reduce
and Map
let getTotal = (element) => {
let fitness = ["e", "l", "m", "n", "t"]
let newMap = new Map(fitness.map(v=>[v,v]))
return element.split('').reduce((op,inp)=>{
if(newMap.has(inp)){
op[inp] = op[inp] || 0
op[inp]++
}
return op
},{})
}
console.log(getTotal('element'))
console.log(getTotal('eleabc'))
You can use join to build a regex with alternation |
and word boundaries, to get total number
let getTotal = (element) =>{
let fitness = ["e", "l", "m", "n", "t"]
let reg = '\\b' + fitness.join('|') + '\\b'
let pattern = new RegExp(reg,'gi')
return (element.match(pattern) || []).length
}
console.log(getTotal('element'))
console.log(getTotal('eleabc'))
Upvotes: 0
Reputation: 520918
One approach would be to iterate the array and do global regex removals of each letter. Then, compare the replaced string length against the original input length to determine the number of occurrences.
function calc_fit(element) {
var fitness_let = ["e", "l", "m", "n", "t"];
for (var i=0; i < fitness_let.length; i++) {
var letter = fitness_let[i];
var numtimes = element.length - element.replace(new RegExp(letter, 'g'), '').length;
console.log(fitness_let[i] + " occurs: " + numtimes + " times.");
}
}
var input = "elements are elemental";
calc_fit(input);
Upvotes: 0