Question

Existe-t-il un BitArray générique dans .NET? J'ai seulement trouvé le non-générique.

Peut-il y avoir un BitArray générique? (c’est-à-dire serait-il raisonnable?)

Modifier:

J'aurais peut-être dû dire que le type-safe n'est pas générique.

En principe, lorsque vous énumérez le type sous la forme object, ne devez-vous pas utiliser int ou bool? Ou l’un d’eux fourni par un autre recenseur membre?

Exemple:

foreach (bool bit in myBitArray)
{

}

Modifier:

Je viens de vérifier l'énumérateur de la classe BitArray, mais tout retourne une propriété .Current sauf <=>:

public virtual object Current
Était-ce utile?

La solution

Non, il n'y en a pas.

Je ne sais même pas quelle partie d'un BitArray serait générique s'il en existait un.

Il ne serait pas difficile de créer une méthode d'extension pour prendre le BitArray et retourner une bool[] ou List<bool> en utilisant une boucle for sur le foreach (bool b in myBitArray.ToList()). La boucle foreach (bool b in myBitArray) n'entraînera pas la boxe puisque vous utiliseriez l'indexeur de bool, et le myBitArray.ToList() foreach (bool b in Enumerable.Cast<bool(myBitArray)) pourrait également être énuméré sans la boxe.

Exemple de méthode d'extension:

static List<bool> ToList( this BitArray ba ) {
    List<bool> l = new List<bool>(ba.Count);
    for ( int i = 0 ; i < ba.Count ; i++ ) {
        l.Add( ba[ i ] );
    }
    return l;
}

Ce que j’ai découvert grâce à un repère rapide (la curiosité m’a dépassée) est que <=> prenait 75% à 85% du temps que <=>. Cela crée la liste à chaque fois. La création de la liste une fois et sa répétition répétée ont pris entre 20% et 25% du temps nécessaire à <=>. Vous ne pouvez en tirer parti que si vous devez parcourir plusieurs fois les <=> valeurs et savoir qu'elles n'auront pas changé depuis le moment où vous avez appelé <=>.

.

<=> a pris 150% du temps passé par <=>.

Encore une autre modification: je dirais que, puisqu'il s'agit d'un jeu, il est probablement logique que vous fassiez tout ce qui est nécessaire pour obtenir une itération très légère sans boxe / unboxing, même si cela signifie écrire votre propre <=>. Vous pourriez gagner du temps et utiliser Reflector pour copier la plupart de étudie le code de <=> puisque la classe est scellée (impossible d’en hériter et d’ajouter des fonctionnalités), juste au cas où il y aurait des optimisations à faire tourner sur des bits à apprendre.

Modifier : supprimez la suggestion de copier le code hors de Reflector. Certaines choses, comme les itérateurs et les fermetures, génèrent un code généré étrange que vous ne voulez pas copier directement de toute façon.

Autres conseils

BitArray est une classe de collection spécialisée de l’ère NET 1.x. Il est assez sûr du type tant que vous utilisez ba.Set(int, bool) et la propriété d'indexeur.

Qu'est-ce que 'not typesafe' est l'énumération, BitArray implémente IEnumerable mais pas IEnumerable < bool > ;. Donc, Joan a raison, utiliser foreach() implique de lancer d'un objet à un autre.

Mais est-ce un problème réel? Les éléments d'un BitArray sont des booléens et n'ont de sens que lorsqu'ils sont combinés avec leur position. Notez que BitArray n’a pas de méthode Add(), mais une Set(i, true).

.

La réponse est donc simple: n'utilisez pas <=>, ni aucun autre produit basé sur IEnumerable. Il ne produit qu'un flux de valeurs vrai / faux qui peut difficilement être utile.

Dans l'extrait suivant, BitArray est parfaitement adapté au type et efficace:

BitArray isEven = ...;
for(int i = 0; i < isEven.Count; i++) 
{
   isEven.Set(i, i % 2 == 0);
}

Vous pouvez itérer BitArray sans boxer ou pour le convertir en List<bool>:

.
public static IEnumerable<bool> GetTypeSafeEnumerator(this BitArray ba) {
    for (int i = 0; i < ba.Length; i++)
        yield return ba[i];
}

Cela devrait être plus rapide que la conversion en liste et prendre beaucoup moins de mémoire.

Bien sûr, cela sera toujours plus lent qu'une simple for boucle, et si vous avez vraiment besoin de performances, utilisez

.
for (int i = 0; i < ba.Length; i++) {
    bool b = ba[i];
    ...
}

Utilisez le MiniBench comme référence:

public static class Class1 {
    private const int N = 10000;
    private const int M = 100;

    public static void Main() {
        var bitArray = new BitArray(N);

        var results1 = new TestSuite<BitArray, int>(
            "Different looping methods")
            .Plus(PlainFor, "Plain for loop")
            .Plus(ForEachBool, "foreach(bool bit in bitArray)")
            .Plus(CastBool, "foreach(bool bit in bitArray.Cast<bool>)")
            .Plus(TypeSafeEnumerator, "foreach(bool bit in bitArray.GetTypeSafeEnumerator())")
            .Plus(UseToList, "foreach(bool bit in bitArray.ToList())")
            .RunTests(bitArray, 0);

        results1.Display(ResultColumns.All, results1.FindBest());

        var results2 = new TestSuite<BitArray, int>(
            "Avoiding repeated conversions")
            .Plus(PlainFor1, "Plain for loop")
            .Plus(CastBool1, "foreach(bool bit in bitArray.Cast<bool>)")
            .Plus(TypeSafeEnumerator1, "foreach(bool bit in bitArray.GetTypeSafeEnumerator())")
            .Plus(UseToList1, "foreach(bool bit in bitArray.ToList())")
            .RunTests(bitArray, 0);

        results2.Display(ResultColumns.All, results2.FindBest());
    }

    private static int PlainFor1(BitArray arg) {
        int j = 0;
        for (int k = 0; k < M; k++) {
            for (int i = 0; i < arg.Length; i++) {
                j += arg[i] ? 1 : 0;
            }
        }
        return j;
    }

    private static int CastBool1(BitArray arg) {
        int j = 0;
        var ba = arg.Cast<bool>();
        for (int k = 0; k < M; k++) {
            foreach (bool b in ba) {
                j += b ? 1 : 0;
            }
        }
        return j;
    }

    private static int TypeSafeEnumerator1(BitArray arg) {
        int j = 0;
        var ba = arg.GetTypeSafeEnumerator();
        for (int k = 0; k < M; k++) {
            foreach (bool b in ba) {
                j += b ? 1 : 0;
            }
        }
        return j;
    }

    private static int UseToList1(BitArray arg) {
        int j = 0;
        var ba = arg.ToList();
        for (int k = 0; k < M; k++) {
            foreach (bool b in ba) {
                j += b ? 1 : 0;
            }
        }
        return j;
    }

    private static int PlainFor(BitArray arg) {
        int j = 0;
        for (int i = 0; i < arg.Length; i++) {
            j += arg[i] ? 1 : 0;
        }
        return j;
    }

    private static int ForEachBool(BitArray arg) {
        int j = 0;
        foreach (bool b in arg) {
            j += b ? 1 : 0;                
        }
        return j;
    }

    private static int CastBool(BitArray arg) {
        int j = 0;
        foreach (bool b in arg.Cast<bool>()) {
            j += b ? 1 : 0;
        }
        return j;
    }

    private static int TypeSafeEnumerator(BitArray arg) {
        int j = 0;
        foreach (bool b in arg.GetTypeSafeEnumerator()) {
            j += b ? 1 : 0;
        }
        return j;
    }

    private static int UseToList(BitArray arg) {
        int j = 0;
        foreach (bool b in arg.ToList()) {
            j += b ? 1 : 0;
        }
        return j;
    }

    public static List<bool> ToList(this BitArray ba) {
        List<bool> l = new List<bool>(ba.Count);
        for (int i = 0; i < ba.Count; i++) {
            l.Add(ba[i]);
        }
        return l;
    }

    public static IEnumerable<bool> GetTypeSafeEnumerator(this BitArray ba) {
        for (int i = 0; i < ba.Length; i++)
            yield return ba[i];
    }
}

Résultats (nom, nombre d'itérations, durée totale, score (le score le plus bas est mauvais)):

============ Different looping methods ============
Plain for loop                                        456899 0:28.087 1,00
foreach(bool bit in bitArray)                         135799 0:29.188 3,50
foreach(bool bit in bitArray.Cast<bool>)               81948 0:33.183 6,59
foreach(bool bit in bitArray.GetTypeSafeEnumerator()) 179956 0:27.508 2,49
foreach(bool bit in bitArray.ToList())                161883 0:27.793 2,79

============ Avoiding repeated conversions ============
Plain for loop                                        5381 0:33.247 1,00
foreach(bool bit in bitArray.Cast<bool>)               745 0:28.273 6,14
foreach(bool bit in bitArray.GetTypeSafeEnumerator()) 2304 0:27.457 1,93
foreach(bool bit in bitArray.ToList())                4603 0:30.583 1,08

Quel serait un exemple d'argument de type générique que vous transmettriez à BitArray<T> s'il existait?

BitArray est défini comme suit:

  

Gère un tableau compact de valeurs en bits,   qui sont représentés comme des booléens,   où true indique que le bit est   on (1) et false indique que le bit est   off (0).

Ce type est un tableau optimisé de bits, rien d’autre. Le rendre générique n'a aucune valeur, car il existe aucun membre qui pourrait être factorisé hors du type. Toute collection spécialisée comme celle-ci peut être considérée comme un type construit fermé d’une collection générique parente. En d'autres termes, List<Boolean> est un peu comme IEnumerable (avec de nombreuses méthodes utiles ajoutées bien sûr).

Modifier: Oui, ce type implémente IEnumerable<T> et non Enumerable.Cast<TResult>. Cela est probablement dû au fait qu'il s'agit d'un type plus ancien et qu'il n'a pas été mis à jour. N'oubliez pas que vous pouvez utiliser <=> pour résoudre ce problème :

yourBitArray.Cast<bool>();

Quelle raison pourriez-vous avoir pour une version générique? Quel type un BitArray pourrait-il éventuellement utiliser à côté de bits, ou de booléens transformés en bits, selon le cas?

Mis à jour: C'est type sûr. Si vous faites un foreach (bit bit dans bitArray), celui-ci apparaîtra en tant qu'objet, mais vous pouvez également le faire tout simplement foreach (bit bool dans bitArray). Cela se produit pour toutes les collections qui implémentent IEnumerable et pas IEnumerable<T>.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top