2010-03-05 5 views

Répondre

32

Il n'existe pas de méthode intégrée pour obtenir la taille/longueur/nombre d'un dictionnaire AS3. Il existe des solutions palliatives: 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 que les entrées sont ajoutées/supprimées, ou compter sur la demande à l'aide d'une simple boucle For itération:

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

Dommage, a dû construire une enveloppe. –

+47

Où est-ce que je vais downvote Adobe pour faire cela? –

+1

Il était nécessaire d'éviter les pièges dans les boucles For, c'est-à-dire ce qui se passe lors de la boucle sur un tableau avec for..in. – Brilliand

0

l'idéal serait de mettre en œuvre juste une enveloppe autour de dictionnaire qui étend la classe Proxy. Cela vous permet de surcharger et d'intercepter l'ajout et la suppression de propriétés du dictionnaire, permettant à la nouvelle classe Dictionnaire 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 undefined pour la cohérence.

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

NE PAS UTILISER CETTE MISE EN ŒUVRE; UTILISEZ CE QUI LE SUIT AU LIEU. 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: La mise en œuvre ci-dessus, bien que l'approche la plus prometteuse qui pourrait avoir travaillé en théorie, est finalement une impasse, car le dictionnaire est intrinsèquement incompatible avec les méthodes d'interface proxy.

D'abord, le setProperty, getProperty et deleteProperty méthodes semblent recevoir typées name paramètres, mais ils sont en fait fortement typé QName objets, qui limitent essentiellement vos clés de String noms de type, tout comme Object et associés tableaux. Dictionary n'est pas lié par cette limitation et permet d'utiliser des instances d'objet comme des clés uniques, de sorte qu'il est intrinsèquement incompatible avec les méthodes de classe Proxy. La documentation de la classe Dictionary contient également une seule note et indique explicitement que les objets QName ne peuvent pas être utilisés en tant que clés.

De même, la méthode nextName de proxy vous empêche de toutes Dictionary sur l'énumération des clés pour la même raison, parce qu'il a une valeur de retour fortement type de String. Donc, même si setProperty, getProperty accepte réellement 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 caractères. Dictionary est simplement dans une classe à part. La meilleure chose à faire est d'implémenter un wrapper comme celui ci-dessus qui expose le dictionnaire sous-jacent pour l'énumération, mais d'autres nécessitent l'appel explicite de méthodes addKey/removeKey avec des noms et valeurs non typés.

Compte tenu de tout ce qui précède, une meilleure mise en œuvre serait la suivante, où vous manipuler le dictionnaire en appelant des méthodes telles que getValue/setValue/removeValue, et avoir accès à une énumération des 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

Vous pouvez utiliser DictionaryUtil:

var dictionaryLength : int = DictionaryUtil.getKeys(d).length; 
Questions connexes