Sto ancora giocando con le tendenze di Twitter. Ho abbastanza dati raccolti che vorrei accelerare l'elaborazione. Voglio assegnare un indice intero a ciascuna parola di tendenza utilizzando un array associativo indicizzato con la parola di tendenza. Di seguito ci sono tre tecniche per aggiungere una nuova parola alla tabella o ottenere l'indice di una vecchia parola.
Il primo usa TRY per catturare l'eccezione quando una parola non è nella tabella. È il più veloce se la parola è presente e il più lento (di gran lunga) se si verifica l'eccezione.
Il secondo usa CONTAINS per verificare se la parola è presente, quindi la aggiunge o la cerca. È il più veloce per aggiungere e il più lento per cercare (perché cerca due volte).
L'ultimo utilizza un valore predefinito di matrice associativa per verificare se il valore recuperato esiste già. Fornisce una buona velocità di compromesso.
Tutti gli esempi hanno un ciclo "t" che viene eseguito due volte. La prima volta che l'array xN è vuoto e deve essere compilato. La seconda volta tutti i valori saranno già presenti.
// Three ways to build a lookup table. No clear winner!
// Goal: assign an integer, starting at 1, to each new
// entry. For timing purposes, use the integer as the
// key and the value. The key will be a string in real
// code. The value will be used as an index elsewhere.
explain = {"create new entry","use existing entry"};
N = 1e5; // several seconds at 1e5
/*
Use TRY to determine when an entry needs to be created.
On the "catch" create the entry. If there is no catch,
the value is already fetched. The "t" loop runs 20X
slower the first time because the "catch" is expensive.
But the second time the "t" loop is the fastest solution.
*/
x1 = [=> ];
For( t = 1, t <= 2, t += 1,
start = HP Time();
For( ix = 1, ix < N, ix += 1,
Try( y = x1[ix], y = (x1[ix] = ix) )
);
stop = HP Time();
Write( Eval Insert( "\!nTry method: ^char((stop - start)/1e6,5,3)^ seconds ^explain[t]^" ) );
);
/*
Use CONTAINS to determine if the entry needs to be created.
Use the if's "then" clause to fetch the existing index or
"else" clause to create a new entry. The "t" loop has the
fastest speed on the first run, by far, and the slowest
speed on the second run.
*/
x2 = [=> ];
For( t = 1, t <= 2, t += 1,
start = HP Time();
For( ix = 1, ix < N, ix += 1,
If( Contains( x2, ix ),
y = x2[ix],
y = (x2[ix] = ix)
)
);
stop = HP Time();
Write( Eval Insert( "\!nContains method: ^char((stop - start)/1e6,5,3)^ seconds ^explain[t]^" ) );
);
/*
Use a DEFAULT value to determine if the entry needs to be
created. Fetch the value for the entry, check for the default
and create if needed. This gives an between value for both
"t" loops. It might be a good compromise choice if no extra
testing will be done and 0 can be used as a default. !y,
below, is faster than y==0.
*/
x3 = [=> 0];
For( t = 1, t <= 2, t += 1,
start = HP Time();
For( ix = 1, ix < N, ix += 1,
y = x3[ix];
If( !y, y = (x3[ix] = ix) );
);
stop = HP Time();
Write( Eval Insert( "\!ndefault 0 method: ^char((stop - start)/1e6,5,3)^ seconds ^explain[t]^" ) );
);
// quick test... the lack of a default value in x1 and x2
// makes them compare not equal, so add it before testing.
x1 << setdefaultvalue( 0 );
x2 << setdefaultvalue( 0 );
Show( x1 == x2, x1 == x3 );
Prova il metodo: 2.851 secondi crea una nuova voce
Prova il metodo: 0.099 secondi utilizzano la voce esistente
Contiene il metodo: 0,209 secondi creano una nuova voce
Contiene il metodo: 0,151 secondi utilizza la voce esistente
metodo 0 predefinito: 0,259 secondi creano una nuova voce
metodo 0 predefinito: 0,117 secondi utilizzano la voce esistente
x1 == x2 = 1;
x1 == x3 = 1;
In rosso, TRY e CONTAINS forniscono i tempi più veloci per le voci esistenti e nuove. In verde, DEFAULT 0 potrebbe essere un buon compromesso. Dipende davvero da quante voci verranno create e quante volte verranno cercate.