2009-12-09 9 views
5

Ho trascorso un po 'del mio tempo libero lavorando una serie di raccolte per ActionScript 3 ma ho raggiunto un roadblock piuttosto serio grazie al modo in cui ActionScript 3 gestisce controlli di uguaglianza all'interno degli oggetti del dizionario.Creazione di un'implementazione "vera" di HashMap con Object Equality in ActionScript 3

Quando si confronta una chiave in un dizionario, ActionScript utilizza l'operatore === per eseguire il confronto, questo ha un effetto collaterale un po 'sgradevole in base al quale solo i riferimenti alla stessa istanza risolveranno true e non gli oggetti di uguaglianza. Ecco cosa voglio dire:

const jonny1 : Person = new Person("jonny", 26); 
const jonny2 : Person = new Person("jonny", 26); 

const table : Dictionary = new Dictionary(); 
table[jonny1] = "That's me"; 

trace(table[jonny1]) // traces: "That's me" 
trace(table[jonny2]) // traces: undefined. 

Il modo in cui sto cercando di combattere questo è quello di fornire un'interfaccia equalizzatore che assomiglia a questo:

public interface Equalizer 
{ 
    function equals(object : Object) : Boolean; 
} 

Questo permette di eseguire un instanceof-Esq. controlla ogni volta che ho bisogno di eseguire un'operazione di uguaglianza all'interno delle mie raccolte (ricadendo sull'operatore === quando l'oggetto non implementa Equalizer); tuttavia, ciò non aggira il fatto che la mia infrastruttura sottostante (l'oggetto dizionario) non ne sia a conoscenza.

Il modo in cui sto attualmente lavorando attorno al problema è iterando attraverso tutte le chiavi del dizionario ed eseguendo il controllo di uguaglianza ogni volta che eseguo un'operazione containsKey() o get() - tuttavia, questo praticamente sconfigge l'intero punto di una hashmap (operazioni di ricerca a basso costo).

Se non riesco a continuare a utilizzare un'istanza di dizionario come supporto per la mappa, come dovrei fare per creare gli hash per le istanze di oggetto univoche passate come chiavi in ​​modo da poter mantenere l'uguaglianza?

risposta

1

Che ne dici di calcolare un codice hash per i tuoi oggetti quando li inserisci e quindi cercarli con il codice hash nel dizionario di backup? L'hashcode dovrebbe confrontare === bene. Ovviamente, ciò richiederebbe un'interfaccia Hashable per i tipi di oggetto anziché l'interfaccia Equalizer, quindi non è molto meno lavoro di quello che si sta già facendo, ma si ottengono le ricerche a basso costo.

1

ne dite invece di fare questo:

public interface Hashable { 
     function hash():String; 
} 

personalmente, mi chiedo, perché si vuole fare questo ... hashing oggetti per ottenere le chiavi ha poco senso se sono mutabili ...

inoltre, si potrebbe considerare l'utilizzo di un approccio diverso, come ad esempio questa fabbrica:

package { 
public class Person { 
    /** 
    * don't use this! 
    * @private 
    */ 
    public function Person(name:String, age:int) { 
    if (!instantiationAllowed) 
    throw new Error("use Person.getPerson instead of constructor"); 
    //... 
    } 
    private static var instantiationAllowed:Boolean = false; 
    private static var map:Object = {}; 
    private static function create(name:String, age:int):Person { 
    instantiationAllowed = true; 
    var ret:Person = new Person(name, age); 
    instantiationAllowed = false; 
    } 
    public static function getPerson(name:String, age:int):Person { 
    var ageMap:Array = map[name]; 
    if (ageMap == null) { 
    map[name] = ageMap = []; 
    return ageMap[age] = Person.create(name, age); 
    } 
    if (ageMap.hasOwnProperty(age)) 
    return ageMap[age]; 
    return ageMap[age] = Person.create(name, age); 
    } 
} 
} 

assicura, c'è solo una persona con un determinato nome e l'età (se questo ha un senso) ...

0

In ogni linguaggio di programmazione,

const jonny1 : Person = new Person("jonny", 26); 
const jonny2 : Person = new Person("jonny", 26); 

sta creando due oggetti completamente diversi che non confrontare con ==, immagino non vedo perché è più di un posto di blocco a causa di AS3

0

Vecchio thread lo so, ma vale comunque la pena di postare.

const jonny1: Persona = nuova Persona ("jonny", 26); const jonny2: Person = new Person ("jonny", 26);

è la creazione di due oggetti completamente diversi che non confrontare con ==, immagino non vedo perché è più di un posto di blocco a causa di AS3

Il problema con AS3/JavaScript/EcmaScript è non che creano due oggetti diversi e equivalenti.

Il problema è che non possono equiparare questi due oggetti equivalenti: solo l'identità funziona, poiché non esistono metodi uguali o hashCode che possono essere sostituiti con la logica di confronto specifica della classe.

Per implementazioni di mappe come oggetti o dizionari dinamici, ciò significa che è necessario utilizzare stringhe o riferimenti come chiavi: non è possibile ripristinare oggetti da una mappa utilizzando oggetti diversi ma equivalenti.

Per ovviare a questo problema, le persone ricorrono a rigorose implementazioni toString (per le mappe dell'oggetto) che non sono desiderabili o al controllo dell'istanza per dizionari, come nell'esempio @ back2dos, che introduce diversi problemi (Si noti inoltre che @ back2dos la soluzione in realtà non garantisce le istanze Person personalizzate poiché esiste una finestra temporale durante la quale i thread asincroni saranno autorizzati ad istanziare nuove Persone).

@ La soluzione di A.Levy è buona, ad eccezione del fatto che in generale i codici hash non sono strettamente necessari per emettere valori univoci (sono pensati per mappare le voci in bucket consentendo ricerche veloci, in cui la differenziazione a grana fine viene eseguita tramite il metodo equals) .

È necessario entrambi un metodo hash e un metodo di uguale, ad es.

public interface IEquable 
{ 
    function equals(object : Object) : Boolean; 
    function hash():String;  
} 
Problemi correlati