最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to count the number of times specific characters are in a string - Stack Overflow

programmeradmin5浏览0评论

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.

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.

Share Improve this question edited Aug 2, 2019 at 12:09 Peter Mortensen 31.6k22 gold badges109 silver badges133 bronze badges asked Aug 2, 2019 at 1:52 Phoenix ShieldPhoenix Shield 1711 silver badge8 bronze badges 2
  • How is this question not a duplicate? It is a very simple question, and more than 1.8 million questions have been asked in the JavaScript tag. – Peter Mortensen Commented Aug 2, 2019 at 12:12
  • 1 @PeterMortensen well, if you can find a dupe, just enter a close vote. – Carl Witthoft Commented Aug 2, 2019 at 12:38
Add a comment  | 

6 Answers 6

Reset to default 11

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);

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;}

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);

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'))

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);

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!'));

发布评论

评论列表(0)

  1. 暂无评论