HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

String sequence in ES6

Submitted by: @import:stackexchange-codereview··
0
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

  • 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
aab


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

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.



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.