@@ -551,31 +551,26 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] {
551551 console . log ( printTable ( _scores , pattern , patternLen , word , wordLen ) ) ;
552552 }
553553
554+ // _bucket is an array of [PrefixArray] we use to keep
555+ // track of scores and matches. After calling `_findAllMatches`
556+ // the best match (if available) is the first item in the array
554557 _bucket . length = 0 ;
558+ _topScore = - 100 ;
555559 _patternStartPos = patternStartPos ;
556- _findAllMatches ( patternLen , wordLen , 0 , [ ] , false ) ;
560+ _findAllMatches ( patternLen , wordLen , 0 , new LazyArray ( ) , false ) ;
557561
558562 if ( _bucket . length === 0 ) {
559563 return undefined ;
560564 }
561565
562- let topMatch = _bucket [ 0 ] ;
563- for ( let i = 1 ; i < _bucket . length ; i ++ ) {
564- let match = _bucket [ i ] ;
565- if ( topMatch [ 0 ] < match [ 0 ] ) {
566- topMatch = match ;
567- }
568- }
569- if ( _debug ) {
570- console . log ( `${ pattern } & ${ word } => ${ topMatch [ 0 ] } points for ${ topMatch [ 1 ] } ` ) ;
571- }
572- return topMatch ;
566+ return [ _topScore , _bucket [ 0 ] . toArray ( ) ] ;
573567}
574568
575- let _bucket : [ number , number [ ] ] [ ] = [ ] ;
569+ let _bucket : LazyArray [ ] = [ ] ;
570+ let _topScore : number = 0 ;
576571let _patternStartPos : number = 0 ;
577572
578- function _findAllMatches ( patternPos : number , wordPos : number , total : number , matches : number [ ] , lastMatched : boolean ) : void {
573+ function _findAllMatches ( patternPos : number , wordPos : number , total : number , matches : LazyArray , lastMatched : boolean ) : void {
579574
580575 if ( _bucket . length >= 10 || total < - 25 ) {
581576 // stop when having already 10 results, or
@@ -595,7 +590,7 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
595590 wordPos -= 1 ;
596591 if ( lastMatched ) {
597592 total -= 5 ; // new gap penalty
598- } else if ( matches . length !== 0 ) {
593+ } else if ( ! matches . isEmpty ( ) ) {
599594 total -= 1 ; // gap penalty after first match
600595 }
601596 lastMatched = false ;
@@ -608,8 +603,8 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
608603 _findAllMatches (
609604 patternPos ,
610605 wordPos - 1 ,
611- matches . length !== 0 ? total - 1 : total ,
612- matches . slice ( 0 ) ,
606+ ! matches . isEmpty ( ) ? total - 1 : total , // gap penalty after first match
607+ matches . slice ( ) ,
613608 lastMatched
614609 ) ;
615610 }
@@ -646,9 +641,56 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
646641
647642 total -= wordPos >= 3 ? 9 : wordPos * 3 ; // late start penalty
648643
649- _bucket . push ( [ total , matches ] ) ;
644+ // dynamically keep track of the current top score
645+ // and insert the current best score at head, the rest at tail
646+ if ( total > _topScore ) {
647+ _topScore = total ;
648+ _bucket . unshift ( matches ) ;
649+ } else {
650+ _bucket . push ( matches ) ;
651+ }
650652}
651653
654+ class LazyArray {
655+
656+ private _parent : LazyArray ;
657+ private _parentLen : number ;
658+ private _data : number [ ] ;
659+
660+ isEmpty ( ) : boolean {
661+ return ! this . _data && ( ! this . _parent || this . _parent . isEmpty ( ) ) ;
662+ }
663+
664+ unshift ( n : number ) {
665+ if ( ! this . _data ) {
666+ this . _data = [ n ] ;
667+ } else {
668+ this . _data . unshift ( n ) ;
669+ }
670+ }
671+
672+ slice ( ) : LazyArray {
673+ const ret = new LazyArray ( ) ;
674+ ret . _parent = this ;
675+ ret . _parentLen = this . _data ? this . _data . length : 0 ;
676+ return ret ;
677+ }
678+
679+ toArray ( ) : number [ ] {
680+ if ( ! this . _data ) {
681+ return this . _parent . toArray ( ) ;
682+ }
683+ const bucket : number [ ] [ ] = [ ] ;
684+ let element = < LazyArray > this ;
685+ while ( element ) {
686+ if ( element . _parent && element . _parent . _data ) {
687+ bucket . push ( element . _parent . _data . slice ( element . _parent . _data . length - element . _parentLen ) ) ;
688+ }
689+ element = element . _parent ;
690+ }
691+ return Array . prototype . concat . apply ( this . _data , bucket ) ;
692+ }
693+ }
652694
653695export function nextTypoPermutation ( pattern : string , patternPos : number ) {
654696
0 commit comments