web-dev-qa-db-fra.com

Obtenir la taille du dictionnaire ActionScript 3

var d: Dictionnaire = nouveau dictionnaire (); 
 d ["a"] = "b"; 
 d ["b"] = "z";

Comment obtenir la longueur/taille du dictionnaire (qui est 2)?

30

Il n'y a pas de méthode intégrée pour obtenir la taille/longueur/nombre d'un dictionnaire AS3. Il existe des solutions de contournement: par exemple, vous pouvez créer une classe de dictionnaire personnalisée qui étend ou enveloppe la classe flash.utils.Dictionary, en ajoutant la fonctionnalité de compteur. Vous pouvez gérer le nombre d'entrées/sorties ajoutées ou supprimées, ou compter à la demande à l'aide d'une simple itération de boucle For:

public static function countKeys(myDictionary:flash.utils.Dictionary):int 
{
    var n:int = 0;
    for (var key:* in myDictionary) {
        n++;
    }
    return n;
}
32
M.A. Hanin

Idéalement, il suffit d'implémenter un wrapper autour de Dictionary qui étend la classe Proxy. Cela vous permet de remplacer et d'intercepter l'ajout et la suppression de propriétés du dictionnaire, ce qui permet à la nouvelle classe Dictionary d'être utilisée exactement comme l'original, avec la même syntaxe et les mêmes capacités, avec l'ajout d'une fonction de longueur qui renvoie le nombre de clés.

Cette implémentation fonctionne comme suit. Lorsqu'une propriété est définie ou supprimée, elle vérifie si la propriété existe déjà (si elle est strictement égale à indéfinie) et incrémente ou décrémente le compteur de longueur interne en conséquence. Cette implémentation supprime également automatiquement une entrée lorsque sa valeur est définie sur non définie pour des raisons de cohérence.

J'ai écrit ce wrapper Dictionnaire juste pour cette question; cela a pris environ 5 minutes et fournit une fonction de longueur qui renvoie la longueur. J'ai choisi d'en faire une fonction plutôt qu'une propriété pour qu'elle n'interfère pas avec les noms de propriétés ni l'énumération des propriétés du dictionnaire.

NE PAS UTILISER CETTE MISE EN ŒUVRE; UTILISER CELUI QUI SUIVENT IT INSTEAD. J'explique pourquoi ci-dessous.

package flos.utils 
{
    import flash.utils.flash_proxy;
    import flash.utils.Proxy;

    public class Dictionary extends Proxy
    {
        private var d:flash.utils.Dictionary;
        private var _length:int = 0;

        public function Dictionary( weakKeys:Boolean = false ) 
        {
            d = new flash.utils.Dictionary( weakKeys );
        }

        public function length():int
        {
            return _length;
        }

        override flash_proxy function getProperty(name:*):* 
        {
            return d[name];
        }

        override flash_proxy function setProperty(name:*, value:*):void 
        {
            if (value === undefined) //delete property when explicitly set to undefined, to enforce rule that an undefined property does not exist and is not counted
            {
                delete this[name];
                return;
            }
            if (d[name] === undefined)
                _length++;
            d[name] = value;
        }

        override flash_proxy function deleteProperty(name:*):Boolean 
        {
            if (d[name] !== undefined)
            {
                delete d[name];
                _length--;
                return true;
            }
            return false;
        }
    }
}

AVERTISSEMENT: L'implémentation ci-dessus, bien que l'approche la plus prometteuse qui aurait pu fonctionner en théorie, est finalement une impasse, dans la mesure où Dictionary est intrinsèquement incompatible avec les méthodes d'interface Proxy.

Premièrement, les méthodes setProperty, getProperty et deleteProperty semblent recevoir des paramètres name non typés, mais ce sont en réalité des objets QName fortement typés, qui restreignent essentiellement vos clés aux noms de type String, comme Object et des tableaux associés. Dictionary n'est pas lié par cette limitation et permet d'utiliser des instances d'objet en tant que clés uniques. Il est donc intrinsèquement incompatible avec les méthodes de la classe Proxy. La documentation de la classe Dictionary comporte également une seule note et indique explicitement que les objets QName ne peuvent pas être utilisés comme clés.

De même, la méthode nextName de Proxy vous empêche d'énumérer toutes les clés Dictionary pour la même raison, car sa valeur de retour de type fort est String. Ainsi, même si setProperty, getProperty a effectivement accepté les clés non typées pour les noms, vous ne pourrez toujours pas les récupérer via une énumération car la méthode nextName renvoie uniquement la chaîne de type. Dictionary est tout simplement une classe à part.

La meilleure chose à faire est d'implémenter un wrapper semblable à celui ci-dessus, qui expose le dictionnaire sous-jacent pour l'énumération, mais d'autres nécessitent l'appel de méthodes addKey/removeKey explicites avec des noms et des valeurs non typés, au lieu d'utiliser le comportement Proxy.

Compte tenu de tout ce qui précède, une meilleure implémentation serait la suivante: vous manipulerez le dictionnaire en appelant des méthodes telles que getValue/setValue/removeValue, et aurez accès à une énumération de clés ainsi qu'à une propriété de longueur:

public class Dictionary
{
    private var d:flash.utils.Dictionary;
    private var _keys:Array;

    public function Dictionary( weakKeys:Boolean = false )
    {
        d = new flash.utils.Dictionary( weakKeys );
        _keys = new Array();
    }

    public function get keys():Array
    {
        return _keys.concat(); //return copy of keys array
    }

    public function get length():int
    {
        return _keys.length;
    }

    public function containsKey( key:* ):Boolean
    {
        return d[key] !== undefined;
    }

    public function setValue( key:*, value:* ):void
    {
        if (value === undefined) //delete property when explicitly set to undefined, to enforce rule that an undefined property does not exist and is not counted
        {
            removeValue( key );
            return;
        }
        if (d[key] === undefined)
        {
            _keys.Push( key );
        }
        d[key] = value;
    }

    public function getValue( key:* ):*
    {
        return d[key];
    }

    public function removeValue( key:* ):Boolean
    {
        if (d[key] !== undefined)
        {
            delete d[key];
            var i:int = _keys.indexOf( key );
            if (i > -1)
                _keys.splice( i, 1 );
            return true;
        }
        return false;
    }
0
Triynko

Vous pouvez utiliser DictionaryUtil:

var dictionaryLength : int = DictionaryUtil.getKeys(d).length;
0
MichelAngelo