I have this code, which counts only adjacent letters in a string and returns the count of each letter.
const inputData = [
'aabbc',
'xxxxvvhjh',
'PPPOM'
];
let output = [];
inputData.forEach(str => {
let strObj = {};
for (let i = 0; i < str.length; i++) {
if (strObj[str[i]] && str[i] === str[i - 1]) {
strObj[str[i]] = strObj[str[i]] += 1;
} else {
strObj[str[i]] = 1;
}
}
const res = Object.keys(strObj).map((key) => `${key}${strObj[key]}`).join('');
output.push(res);
});
console.log(output);
Output
[ 'a2b2c1','x4v2h1j1h1','P3O1M1']
3 Answers 3
The observation by George is correct- it does iterate over the inputs twice. The prescribed approach seems to work (see demonstration at the end of the post).
Suggestions
line to increment count- extra assignment
This line looks like it is doing more than it needs to:
strObj[str[i]] = strObj[str[i]] += 1;
That appears to be
- setting the value of
strObj[str[i]]
tostrObj[str[i]]
+ 1 - assigning that value to
strObj[str[i]]
again
It could be simplified to just:
strObj[str[i]] += 1;
or even more simply:
strObj[str[i]]++;
using forEach
with push
Whenever a forEach
loop pushes into an array e.g. for output
, this can be simplified to array.map()
prefer const
over let
Variables output
and strObj
can be declared with const
instead, since they are only assigned once. This can help avoid accidental re-assignment and other bugs.
Current code simplified
This code incorporates the advice from suggestions above.
const inputData = [
'aabbc',
'xxxxvvhjh',
'PPPOM'
];
const output = inputData.map(str => {
const strObj = {};
for (let i = 0; i < str.length; i++) {
if (strObj[str[i]] && str[i] === str[i - 1]) {
strObj[str[i]]++;
} else {
strObj[str[i]] = 1;
}
}
return Object.keys(strObj).map((key) => `${key}${strObj[key]}`).join('');
});
console.log(output);
Simplified code with one iteration over each input
This code follows the advice George described, plus suggestions above
const inputData = [
'aabbc',
'xxxxvvhjh',
'PPPOM'
];
const output = inputData.map(str => {
let lastChar, count = 0;
const retVals = [];
for (let i = 0; i < str.length; i++) {
if (!i || lastChar === str[i]) {
count++;
} else if (str[i] !== str[i - 1]) {
retVals.push(str[i - 1], count);
count = 1;
if (i === str.length - 1) {
retVals.push(str[i], 1);
}
}
lastChar = str[i];
}
return retVals.join('');
});
console.log(output);
Bug
Your code has a bug.
The result for the string "xxxxvvhjh"
you defined to be "x4v2h1j1h1"
however your function returns "x4v2h1j1"
not counting the final h
The reason is that you are using an object to map the letters. When the same letter appears more than once but are not adjacent you only output that character once. Eg the string "hhahhh"
your function returns "h3a1"
rather than "h2a1h3"
That said your question states
"which counts only adjacent letters in string and gives out count."
Which contradicts the output you have given
[ 'a2b2c1','x4v2h1j1h1','P3O1M1']
Assuming that the output you have given is correct and with the title "run length coder" (assume that is encoder) which reinforces the assumption and the fact that you give the wrong result for "hhahhh"
I will presume you are attempting Run length encoding
There is no easy way to correct your code as it is fundamentally flawed. All we can do is start a complete rewrite.
There is no need to use a map as you have done with strObj
. The encoding can be done in a single pass
Run length encoding
Is very simple and fast lossless compression method.
You code should be as functions. With a function to encode a single string, and a second function to encode an array of strings.
Encode a string
Assuming that the string to encode is always 1 or more characters long
function encodeStr(str) {
var i = 1, char = str[i], count = 1, result = "";
while (i < str.length) {
const next = str[i++];
count = next === char ? count + 1 : (result += char + count, 1);
char = next;
}
return result + char + count;
}
Encode strings
To encode an array of strings a second function just maps the array using the above function.
const encodeStrs = strs => strs.map(encodeStr);
To use
function encodeStr(str) {
var i = 1, char = str[i], count = 1, result = "";
while (i < str.length) {
const next = str[i++];
count = next === char ? count + 1 : (result += char + count, 1);
char = next;
}
return result + char + count;
}
const encodeStrs = strs => strs.map(encodeStr);
console.log(encodeStrs(["aabbc", "xxxxvvhjh", "PPPOM"]))
-
\$\begingroup\$ Thanks @Blindman67, What does this part do? (result += char + count, 1) \$\endgroup\$uday8486– uday84862021年06月21日 04:23:49 +00:00Commented Jun 21, 2021 at 4:23
-
\$\begingroup\$ @uday8486 The
()
defines a group developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… with the comma separating expressions, the last expression,1
is assigned tocount
at the start of the linecount =
\$\endgroup\$Blindman67– Blindman672021年06月21日 07:41:51 +00:00Commented Jun 21, 2021 at 7:41 -
\$\begingroup\$ @uday8486 ... And a link for more on the comma developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… \$\endgroup\$Blindman67– Blindman672021年06月21日 07:44:26 +00:00Commented Jun 21, 2021 at 7:44
I am not familiar with javascript, but seems like you are iterating over inputs twice, you really just need to iterate over it once. here is how(I might write a pseudo code later) at start:
create variable(char)
lastCharacter
and (int)characterCount
create javascript equivalent of c++ struct (I will name this struct "AdjacentCharacters") with variables:
character
andcount
create list/vector(or any other resizable array type) of "AdjacentCharacters".
in each iteration:
- increment characterCount
- keep track of current character
- at the end of the iteration set lastCharacter to currentCharacter
- but before that, compare lastCharacter to currentCharacter, if it matchs or it's first iteration of the loop(since you don't have lastCharacter if it's first)increment characterCount.
- if it does not match then push in the "AdjacentCharacters" list and set character count to 0
Summary: you are basicaly iterating over string and keeping track of how many same characters you have met, if you meet different character than you reset characterCount to 0, because chain of same characters was broken, and you write down how many same characters you have met and what was that same character to the "AdjacentCharacters" struct and push it to list of "AdjacentCharacters".
Explore related questions
See similar questions with these tags.