Friday, May 17, 2024
 Popular · Latest · Hot · Upcoming
44
rated 0 times [  45] [ 1]  / answers: 1 / hits: 72142  / 11 Years ago, sun, october 20, 2013, 12:00:00

I want to count the number of occurrences of each character in a given string using JavaScript.


For example:


var str = "I want to count the number of occurrences of each char in this string";

Output should be:


h = 4;
e = 4; // and so on

I tried searching Google, but didn't find any answer. I want to achieve something like this; order doesn't matter.


More From » javascript

 Answers
5

This is nice and simple in JavaScript (or any other language that supports arbitrary key/value maps). And for key/value mapping, in JavaScript you have two options: objects and Map instances. In most cases where the keys are arbitrary as in this case, a Map is the better choice (more on MDN). Here's how that looks:




// The string
const str = I want to count the number of occurrences of each char in this string;

// A map for the character=>count mappings
const counts = new Map();

// Loop through the string...
for (const ch of str) {
// Get the count for it, if we have one; we'll get `undefined` if we don't
// know this character yet. Using nullish coalescing (`??`), we can turn
// that `undefined` into a `0`. (In obsolete environments that don't
// support nullish coalescing, for this use case we could use the logical
// OR operator [`||`] instead to use `0` instead of any falsy value, since
// A) `undefined` is falsy, and B) None of the count values we're tracking
// will be falsy because they're all non-zero. For some other use cases,
// we'd need to use a conditional testing `undefined` explicitly.)
const count = counts.get(ch) ?? 0;

// Add one and store the result
counts.set(ch, count + 1);
}

// Show the counts
for (const [ch, count] of counts) {
console.log(`${ch} count: ${counts.get(ch)}`);
}

.as-console-wrapper {
max-height: 100% !important;
}




With a Map, the order of the iteration at the end will be the order in which the keys were first added to the Map. You can see that above, I is the first character we see in the output, followed by a space, followed by w...


Here's what it looks like with an object, but beware of using objects for arbitrary key/value maps, and if you use them that way, create them without a prototype so they don't have inherited properties (see the MDN link above for details):




// The string
const str = I want to count the number of occurrences of each char in this string;

// An object for the character=>count mappings
// We use `Object.create(null)` so the object doesn't have any inherited properties
const counts = Object.create(null);

// Loop through the string...
for (const ch of str) {
// Get the count for it, if we have one; we'll get `undefined` if we don't
// know this character yet. Using nullish coalescing (`??`), we can turn
// that `undefined` into a `0`. (In obsolete environments that don't
// support nullish coalescing, for this use case we could use the logical
// OR operator [`||`] instead to use `0` instead of any falsy value, since
// A) `undefined` is falsy, and B) None of the count values we're tracking
// will be falsy because they're all non-zero. For some other use cases,
// we'd need to use a conditional testing `undefined` explicitly.)
const count = counts[ch] ?? 0;

// Add one and store the result
counts[ch] = count + 1;
}

// Show the counts
for (const ch in counts) {
console.log(`${ch} count: ${counts[ch]}`);
}

.as-console-wrapper {
max-height: 100% !important;
}




The order of that will also be the order the objects properties were first added except that property names that are numeric strings qualifying as array indexes will be visited first, in ascending numeric order. Here's both options above processing the string "abc321" — notice the difference in the order of the results:




function withAMap(str) {
// A map for the character=>count mappings
const counts = new Map();

// Loop through the string...
for (const ch of str) {
// Get the count for it, if we have one; we'll get `undefined` if we don't
// know this character yet. Using nullish coalescing (`??`), we can turn
// that `undefined` into a `0`. (In obsolete environments that don't
// support nullish coalescing, for this use case we could use the logical
// OR operator [`||`] instead to use `0` instead of any falsy value, since
// A) `undefined` is falsy, and B) None of the count values we're tracking
// will be falsy because they're all non-zero. For some other use cases,
// we'd need to use a conditional testing `undefined` explicitly.)
const count = counts.get(ch) ?? 0;

// Add one and store the result
counts.set(ch, count + 1);
}

// Show the counts
for (const [ch, count] of counts) {
console.log(`${ch} count: ${counts.get(ch)}`);
}
}

function withAnObject(str) {
// An object for the character=>count mappings
// We use `Object.create(null)` so the object doesn't have any inherited properties
const counts = Object.create(null);

// Loop through the string...
for (const ch of str) {
// Get the count for it, if we have one; we'll get `undefined` if we don't
// know this character yet. Using nullish coalescing (`??`), we can turn
// that `undefined` into a `0`. (In obsolete environments that don't
// support nullish coalescing, for this use case we could use the logical
// OR operator [`||`] instead to use `0` instead of any falsy value, since
// A) `undefined` is falsy, and B) None of the count values we're tracking
// will be falsy because they're all non-zero. For some other use cases,
// we'd need to use a conditional testing `undefined` explicitly.)
const count = counts[ch] ?? 0;

// Add one and store the result
counts[ch] = count + 1;
}

// Show the counts
for (const ch in counts) {
console.log(`${ch} count: ${counts[ch]}`);
}
}

const str = abc321;
console.log(With a Map:);
withAMap(str);
console.log(With an object:);
withAnObject(str);

.as-console-wrapper {
max-height: 100% !important;
}




[#74854] Saturday, October 19, 2013, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
tayla

Total Points: 681
Total Questions: 102
Total Answers: 108

Location: Marshall Islands
Member since Tue, Sep 21, 2021
3 Years ago
tayla questions
Fri, Mar 5, 21, 00:00, 3 Years ago
Wed, Oct 28, 20, 00:00, 4 Years ago
Thu, Apr 9, 20, 00:00, 4 Years ago
;