@@ -7,24 +7,32 @@ import { DefaultMap, hash } from './utils.js'
77 * exploit the key-value structure of the data to run efficiently.
88 */
99export class Index < K , V > {
10- #inner: DefaultMap < K , [ V , number ] [ ] >
11- #changedKeys: Set < K >
10+ #inner: DefaultMap < K , DefaultMap < string , [ V , number ] > >
1211
1312 constructor ( ) {
14- this . #inner = new DefaultMap < K , [ V , number ] [ ] > ( ( ) => [ ] )
15- this . #changedKeys = new Set < K > ( )
13+ this . #inner = new DefaultMap < K , DefaultMap < string , [ V , number ] > > (
14+ ( ) =>
15+ new DefaultMap < string , [ V , number ] > ( ( ) => [ undefined as any as V , 0 ] ) ,
16+ )
17+ // #inner is as map of:
18+ // {
19+ // [key]: {
20+ // [hash(value)]: [value, multiplicity]
21+ // }
22+ // }
1623 }
1724
1825 toString ( indent = false ) : string {
1926 return `Index(${ JSON . stringify (
20- [ ...this . #inner] ,
27+ [ ...this . #inner] . map ( ( [ k , valueMap ] ) => [ k , [ ... valueMap ] ] ) ,
2128 undefined ,
2229 indent ? ' ' : undefined ,
2330 ) } )`
2431 }
2532
2633 get ( key : K ) : [ V , number ] [ ] {
27- return this . #inner. get ( key )
34+ const valueMap = this . #inner. get ( key )
35+ return [ ...valueMap . values ( ) ]
2836 }
2937
3038 entries ( ) {
@@ -36,78 +44,44 @@ export class Index<K, V> {
3644 }
3745
3846 has ( key : K ) : boolean {
39- return this . #inner. has ( key ) && this . #inner . get ( key ) . length > 0
47+ return this . #inner. has ( key )
4048 }
4149
4250 get size ( ) : number {
43- let count = 0
44- for ( const [ , values ] of this . #inner. entries ( ) ) {
45- if ( values . length > 0 ) {
46- count ++
47- }
48- }
49- return count
51+ return this . #inner. size
5052 }
5153
5254 addValue ( key : K , value : [ V , number ] ) : void {
53- const values = this . #inner. get ( key )
54- values . push ( value )
55- this . #changedKeys. add ( key )
56- }
57-
58- append ( other : Index < K , V > ) : void {
59- for ( const [ key , otherValues ] of other . entries ( ) ) {
60- const thisValues = this . #inner. get ( key )
61- for ( const value of otherValues ) {
62- thisValues . push ( value )
63- }
64- this . #changedKeys. add ( key )
65- }
66- }
67-
68- compact ( keys : K [ ] = [ ] ) : void {
69- // If no keys specified, use the changed keys
70- const keysToProcess = keys . length === 0 ? [ ...this . #changedKeys] : keys
71-
72- for ( const key of keysToProcess ) {
73- if ( ! this . #inner. has ( key ) ) continue
74-
75- const values = this . #inner. get ( key )
76- const consolidated = this . consolidateValues ( values )
77-
78- // Remove the key entirely and re-add only if there are non-zero values
79- this . #inner. delete ( key )
80- if ( consolidated . length > 0 ) {
81- this . #inner. get ( key ) . push ( ...consolidated )
82- }
83- }
84-
85- // Clear the changed keys after compaction
86- if ( keys . length === 0 ) {
87- this . #changedKeys. clear ( )
88- } else {
89- // Only remove the keys that were explicitly compacted
90- for ( const key of keys ) {
91- this . #changedKeys. delete ( key )
55+ const [ val , multiplicity ] = value
56+ const valueMap = this . #inner. get ( key )
57+ const valueHash = hash ( val )
58+ const [ , existingMultiplicity ] = valueMap . get ( valueHash )
59+ const newMultiplicity = existingMultiplicity + multiplicity
60+ if ( multiplicity !== 0 ) {
61+ if ( newMultiplicity === 0 ) {
62+ valueMap . delete ( valueHash )
63+ } else {
64+ valueMap . set ( valueHash , [ val , newMultiplicity ] )
9265 }
9366 }
9467 }
9568
96- private consolidateValues ( values : [ V , number ] [ ] ) : [ V , number ] [ ] {
97- const consolidated = new Map < string , { value : V ; multiplicity : number } > ( )
98-
99- for ( const [ value , multiplicity ] of values ) {
100- const valueHash = hash ( value )
101- if ( consolidated . has ( valueHash ) ) {
102- consolidated . get ( valueHash ) ! . multiplicity += multiplicity
103- } else {
104- consolidated . set ( valueHash , { value, multiplicity } )
69+ append ( other : Index < K , V > ) : void {
70+ for ( const [ key , otherValueMap ] of other . entries ( ) ) {
71+ const thisValueMap = this . #inner. get ( key )
72+ for ( const [
73+ valueHash ,
74+ [ value , multiplicity ] ,
75+ ] of otherValueMap . entries ( ) ) {
76+ const [ , existingMultiplicity ] = thisValueMap . get ( valueHash )
77+ const newMultiplicity = existingMultiplicity + multiplicity
78+ if ( newMultiplicity === 0 ) {
79+ thisValueMap . delete ( valueHash )
80+ } else {
81+ thisValueMap . set ( valueHash , [ value , newMultiplicity ] )
82+ }
10583 }
10684 }
107-
108- return [ ...consolidated . values ( ) ]
109- . filter ( ( { multiplicity } ) => multiplicity !== 0 )
110- . map ( ( { value, multiplicity } ) => [ value , multiplicity ] )
11185 }
11286
11387 join < V2 > ( other : Index < K , V2 > ) : MultiSet < [ K , [ V , V2 ] ] > {
@@ -116,23 +90,23 @@ export class Index<K, V> {
11690 // We want to iterate over the smaller of the two indexes to reduce the
11791 // number of operations we need to do.
11892 if ( this . size <= other . size ) {
119- for ( const [ key , values1 ] of this . entries ( ) ) {
93+ for ( const [ key , valueMap ] of this . entries ( ) ) {
12094 if ( ! other . has ( key ) ) continue
121- const values2 = other . get ( key )
122- for ( const [ val1 , mul1 ] of values1 ) {
123- for ( const [ val2 , mul2 ] of values2 ) {
95+ const otherValues = other . get ( key )
96+ for ( const [ val1 , mul1 ] of valueMap . values ( ) ) {
97+ for ( const [ val2 , mul2 ] of otherValues ) {
12498 if ( mul1 !== 0 && mul2 !== 0 ) {
12599 result . push ( [ [ key , [ val1 , val2 ] ] , mul1 * mul2 ] )
126100 }
127101 }
128102 }
129103 }
130104 } else {
131- for ( const [ key , values2 ] of other . entries ( ) ) {
105+ for ( const [ key , otherValueMap ] of other . entries ( ) ) {
132106 if ( ! this . has ( key ) ) continue
133- const values1 = this . get ( key )
134- for ( const [ val2 , mul2 ] of values2 ) {
135- for ( const [ val1 , mul1 ] of values1 ) {
107+ const values = this . get ( key )
108+ for ( const [ val2 , mul2 ] of otherValueMap . values ( ) ) {
109+ for ( const [ val1 , mul1 ] of values ) {
136110 if ( mul1 !== 0 && mul2 !== 0 ) {
137111 result . push ( [ [ key , [ val1 , val2 ] ] , mul1 * mul2 ] )
138112 }
0 commit comments