0

I've been trying to come up with an answer to this exercise where I have to count the frequency of characters in a string.

Suppose I have a string "haphqap" and I want the output as "h2a2p2q1".

I am able to achieve with two for loops. If anyone can provide me with some efficient answer.

var strin = "haphqap";

var count = {}

for (var pos = 0; pos < strin.length; pos++) {
  if (!(strin[pos] in count)) {
    count[strin[pos]] = 1;
  } else {
    count[strin[pos]]++;
  }
}

console.log(count) //{ h: 2, a: 2, p: 2, q: 1 }

Using this object I can make a string.

I want to know if there is any another way of doing it?

6
  • 1
    That's a pretty good way to do it, really. Commented Aug 27, 2019 at 10:56
  • 1
    Your approach is already quite efficient and should run in O(N), are you looking for a more efficient approach or just another way to solve your problem? Commented Aug 27, 2019 at 10:59
  • @NickParsons Here I am using two for loops to reach the result. I was looking for some other way if any where we have only one loop. Commented Aug 27, 2019 at 11:08
  • @PrateekBirla overall, each loop is going to run N times, N times when constructing the string from the object, so your program will still run in O(N) which is efficient for this sort of thing. At the end of the day, you're going to need some sort of structure to store the occurrences of each letter (you've used an object) and then something to convert that structure back into a string. Adding one additional loop to do this won't cause too much of a performance drain Commented Aug 27, 2019 at 11:15
  • 1
    @NickParsons I guess you are right.We need one structure to store the count and some loop to convert it back to string. Thanks. Commented Aug 27, 2019 at 11:30

2 Answers 2

0

That's the preferred and simplest way to solve the counting problem. To make a string from that object, use map and join:

const str = Object.entries(count).map(e => e.join("")).join("");

Or:

const str = Object.entries(count).map(([a, b]) => a + b).join("");

Note that there won't be any order because you're using an object.

Sign up to request clarification or add additional context in comments.

Comments

0

You can use reduce.

edit: meet te requirements

//we declare and initialize our string
let myString = "HELLO WORLD";

// we split our variable to get an array
let arrMyString = myString.split('');
// result: [ "H", "E", "L", "L", "O", " ", "W", "O", "R", "L", "D" ]


// now we use Array.reduce 
let myResult = arrMyString.reduce(function(accumulator, currentValue) {

  // accumulator start with empty string, see second parameter of Array.reduce
  let indexCurrentValue = accumulator.indexOf(currentValue);


  if (indexCurrentValue == -1) {
    //char is NOT found in accumulator
    accumulator = accumulator.concat(currentValue, "1");
  } else {
    //char IS found in accumulator
    //step 1 : slice the string
    let myPrettySlice = accumulator.slice(indexCurrentValue);
    //we get the first intrigers before matching any thing else 
    // example myPrettySlice::  g55r99y12h14.slice( [index of y] ) -> y12h14

    let getCountCurrentIndex = /([0-9]{1,})/.exec(myPrettySlice)[0];
    // example would give 12
    //reforming all
    accumulator = accumulator
      .split(currentValue.concat(getCountCurrentIndex))
      .join(currentValue.concat(parseInt(getCountCurrentIndex, 10) + 1));



  }


  return accumulator;
}, "");

console.log(myResult);

3 Comments

Thanks for the solution. But here we are getting the object in result i.e. { H: 1, E: 1, L: 3, O: 2, " ": 1, W: 1, R: 1, D: 1 } . To convert it back to string we might use an another loop right?
we can use the reduce function to achieve desired result, lemme update my answer, sorry for bad reading :(
@PrateekBirla i have update'd my answer it's not the most elegant way and there is room for improvement but i hope it helps you on your way

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.