patternjavascriptMinor
String sequence in ES6
Viewed 0 times
es6stringsequence
Problem
Given an unique string that represents a sequence of characters, the class should implement three methods (getNextChar, getNextString and the genSequence generator).
How it works
The next string of an existing string works like a dictionary, only the length doesn't change as long as there are still characters to fulfill.
This is not homework, but a user in Stack Overflow chat presented the challenge and I considered taking it to a higher level.
```
class SeqString {
constructor (sequence) {
this._sequence = sequence;
this._first = sequence[0];
this._last = sequence.slice(-1);
return this;
}
getNextChar (char) {
let seq = this._sequence,
index = (seq.indexOf(char) + 1) % seq.length;
return seq[index];
}
getNextString (str) {
let last = str.slice(-1),
init = str.slice(0, str.length - 1),
lastOfSeq = this._last,
firstOfSeq = this._first;
// If it is overflowing
if (last === lastOfSeq) {
let trail = 1,
i = init.length;
// Look for an index that won't overflow
while (i-- && init[i] === lastOfSeq) ++trail;
// If there is no such index, then the result is a new sequence
// with an increased length
if (i === -1) return firstOfSeq.repeat(trail + 1);
// If there is, change the matching character at the index
// and reset every character after that
str = init.slice(0, i) + this.getNextChar(init[i]) +
firstOfSeq.repeat(trail);
return str;
}
return init + this.getNextChar(last);
}
*genSequence (str) {
let newStr = this.get
How it works
- We give a sequence of characters. For example: "abc"
- We give a starting string. For example: "a"
- The generator yields the following strings infinitely.
The next string of an existing string works like a dictionary, only the length doesn't change as long as there are still characters to fulfill.
a
b
c
aa
ab
ac
ba
..
cc
aaa
aabThis is not homework, but a user in Stack Overflow chat presented the challenge and I considered taking it to a higher level.
```
class SeqString {
constructor (sequence) {
this._sequence = sequence;
this._first = sequence[0];
this._last = sequence.slice(-1);
return this;
}
getNextChar (char) {
let seq = this._sequence,
index = (seq.indexOf(char) + 1) % seq.length;
return seq[index];
}
getNextString (str) {
let last = str.slice(-1),
init = str.slice(0, str.length - 1),
lastOfSeq = this._last,
firstOfSeq = this._first;
// If it is overflowing
if (last === lastOfSeq) {
let trail = 1,
i = init.length;
// Look for an index that won't overflow
while (i-- && init[i] === lastOfSeq) ++trail;
// If there is no such index, then the result is a new sequence
// with an increased length
if (i === -1) return firstOfSeq.repeat(trail + 1);
// If there is, change the matching character at the index
// and reset every character after that
str = init.slice(0, i) + this.getNextChar(init[i]) +
firstOfSeq.repeat(trail);
return str;
}
return init + this.getNextChar(last);
}
*genSequence (str) {
let newStr = this.get
Solution
Well, to me it looks pretty good. I've made a few minor tweaks, mainly renaming variables, removing unneeded temp variables and renaming the class and methods, to make the code a little more self documenting.
There was one thing that struct me as odd. Your class only works with charSets which contain unique chars. "ppen" will output "p" ten times.
I would definitely add a pruning feature to remove any duplicates, that would make it a more robust class. Something like this first snippet below.
Otherwise, I've removed all the comments, I feel it remains just as readable as your initial version.
I've also rewritten your test a little bit, also just minor tweaks.
Again, nothing major, hope my comments are helpful.
There was one thing that struct me as odd. Your class only works with charSets which contain unique chars. "ppen" will output "p" ten times.
I would definitely add a pruning feature to remove any duplicates, that would make it a more robust class. Something like this first snippet below.
const CharStitcher = (function(){
class CharStitcher {
constructor (string) {
string = CharStitcher.pruneChars(string);
this._str = string;
this._1st = string[0];
this._last = string[ string.length -1 ];
return this;
}
next (char) {
return this._str[ ( this._str.indexOf(char) + 1 ) % this._str.length ];
}
genString (str) {
let lastChar = str.slice(-1);
let otherChars = str.slice(0, str.length - 1);
if (lastChar === this._last) {
let charAt = 1;
let upTo = otherChars.length;
while ( otherChars[upTo] === this._last && --upTo ) ++charAt;
if ( upTo === -1 ) return this._1st.repeat( charAt + 1 );
return otherChars.slice( 0, upTo ) + this.next( otherChars[upTo] ) + this._1st.repeat( charAt );
}
return otherChars + this.next(lastChar);
}
*stitch (str, newStr) {
newStr = this.genString(str);
yield newStr, yield* this.stitch(newStr);
}
}
CharStitcher.pruneChars = function (source, pruned){
pruned = {}
source.split('').forEach(function(char){
if(!Object.prototype.hasOwnProperty.call(pruned, char)){
pruned[char] = undefined;
}
})
return Object.keys(pruned).join('');
}
return CharStitcher;
})();
Otherwise, I've removed all the comments, I feel it remains just as readable as your initial version.
class CharStitcher {
constructor (string) {
this._str = string;
this._1st = string[0];
this._last = string[ string.length -1 ];
return this;
}
next (char) {
return this._str[ ( this._str.indexOf(char) + 1 ) % this._str.length ];
}
genString (str) {
let lastChar = str.slice(-1);
let otherChars = str.slice(0, str.length - 1);
if (lastChar === this._last) {
let charAt = 1;
let upTo = otherChars.length;
while ( otherChars[upTo] === this._last && --upTo ) ++charAt;
if ( upTo === -1 ) return this._1st.repeat( charAt + 1 );
return otherChars.slice( 0, upTo ) + this.next( otherChars[upTo] ) + this._1st.repeat( charAt );
}
return otherChars + this.next(lastChar);
}
*stitch (str, newStr) {
newStr = this.genString(str);
yield newStr;
yield* this.stitch(newStr);
}
}I've also rewritten your test a little bit, also just minor tweaks.
function test (charSet, startStr, times = 10) {
let progress = new CharStitcher(charSet).stitch(startStr);
while ( times-- ) console.log(progress.next().value);
}
test("pen", "p", 10);class CharStitcher {
constructor (string) {
this._str = string;
this._1st = string[0];
this._last = string[ string.length -1 ];
return this;
}
next (char) {
return this._str[ ( this._str.indexOf(char) + 1 ) % this._str.length ];
}
genString (str) {
let lastChar = str.slice(-1);
let otherChars = str.slice(0, str.length - 1);
if (lastChar === this._last) {
let charAt = 1;
let upTo = otherChars.length;
while ( otherChars[upTo] === this._last && upTo-- && ++charAt);
if ( upTo === -1 ) return this._1st.repeat( charAt + 1 );
return otherChars.slice( 0, upTo ) + this.next( otherChars[upTo] ) + this._1st.repeat( charAt );
}
return otherChars + this.next(lastChar);
}
*stitch (str, newStr) {
newStr = this.genString(str);
yield newStr;
yield* this.stitch(newStr);
}
}
function test (charSet, startStr, times = 10) {
let progress = new CharStitcher(charSet).stitch(startStr);
while ( times-- ) console.log(progress.next().value);
}
test("pen", "p", 10);
Again, nothing major, hope my comments are helpful.
Code Snippets
class CharStitcher {
constructor (string) {
this._str = string;
this._1st = string[0];
this._last = string[ string.length -1 ];
return this;
}
next (char) {
return this._str[ ( this._str.indexOf(char) + 1 ) % this._str.length ];
}
genString (str) {
let lastChar = str.slice(-1);
let otherChars = str.slice(0, str.length - 1);
if (lastChar === this._last) {
let charAt = 1;
let upTo = otherChars.length;
while ( otherChars[upTo] === this._last && --upTo ) ++charAt;
if ( upTo === -1 ) return this._1st.repeat( charAt + 1 );
return otherChars.slice( 0, upTo ) + this.next( otherChars[upTo] ) + this._1st.repeat( charAt );
}
return otherChars + this.next(lastChar);
}
*stitch (str, newStr) {
newStr = this.genString(str);
yield newStr;
yield* this.stitch(newStr);
}
}function test (charSet, startStr, times = 10) {
let progress = new CharStitcher(charSet).stitch(startStr);
while ( times-- ) console.log(progress.next().value);
}
test("pen", "p", 10);Context
StackExchange Code Review Q#98058, answer score: 2
Revisions (0)
No revisions yet.