Domanda

Esiste un BitArray generico in .NET? Ho trovato solo quello non generico.

Può esserci un BitArray generico? (cioè sarebbe ragionevole?)


Modifica:

Forse avrei dovuto dire che non è un tipo sicuro.

Fondamentalmente quando si enumera il tipo come object, non dovrebbe essere int o bool? O uno di questi fornito in un altro enumeratore dei membri?


Esempio:

foreach (bool bit in myBitArray)
{

}

Modifica:

Ho appena controllato l'enumeratore della classe BitArray, ma tutto restituisce una .Current tranne <=> proprietà:

public virtual object Current
È stato utile?

Soluzione

No, non c'è.

Non sono nemmeno sicuro di quale parte di un BitArray sarebbe generica se ce ne fosse una.

Non sarebbe difficile creare un metodo di estensione per prendere BitArray e restituire un bool[] o List<bool> usando un for loop sul foreach (bool b in myBitArray.ToList()). Il ciclo foreach (bool b in myBitArray) non implicherebbe il pugilato poiché si userebbe l'indicizzatore del bool e il myBitArray.ToList() foreach (bool b in Enumerable.Cast<bool(myBitArray)) potrebbe essere enumerato anche senza il pugilato.

Esempio di metodo di estensione:

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;
}

Quello che ho trovato da un rapido benchmark (la curiosità mi ha superato) è stato che <=> ha impiegato dal 75% all'85% delle volte che <=>. Questo crea l'elenco ogni volta. La creazione dell'elenco una volta e l'iterazione più volte hanno richiesto dal 20% al 25% del tempo impiegato da <=>. Puoi trarne vantaggio solo se devi ripetere più volte i <=> valori e sapere che non saranno cambiati dal momento in cui hai chiamato <=>.

<=> ha impiegato il 150% del tempo impiegato <=>.

Ancora un'altra modifica: direi che, dato che si tratta di un gioco, probabilmente ha senso fare tutto ciò che serve per avere un'iterazione molto snella senza boxe / unboxing, anche se ciò significa scrivere il tuo <=>. Puoi risparmiare tempo e utilizzare Reflector per copiare la maggior parte di studia il codice di <=> poiché la classe è sigillata (non può ereditare e aggiungere funzionalità), nel caso in cui ci siano ottimizzazioni a bit-bit da cui imparare.

Modifica: ho suggerito di copiare il codice da Reflector. Alcune cose, come iteratori e chiusure, producono un codice generato strano che non si desidera copiare direttamente.

Altri suggerimenti

BitArray è una classe di raccolta specializzata dell'era NET 1.x. È abbastanza sicuro se si utilizza ba.Set(int, bool) e la proprietà dell'indicizzatore.

Ciò che non è 'typesafe' è l'enumerazione, BitArray implementa IEnumerable ma non IEnumerable < bool > ;. Quindi Joan ha ragione, usare foreach() implica il cast dall'oggetto al bool.

Ma è un vero problema? Gli elementi in un BitArray sono booleani e significativi solo se combinati con la loro posizione. Nota che BitArray non ha un metodo Add(), ma solo un Set(i, true).

Quindi la risposta semplice è: non usare <=> o qualsiasi altra cosa basata su IEnumerable. Produce solo un flusso di valori vero / falso che difficilmente può essere utile.

Nel seguente frammento BitArray è perfettamente sicuro ed efficiente:

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

Puoi iterare BitArray senza boxe o convertendolo in List<bool>:

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

Questo dovrebbe essere più veloce della conversione in elenco e sicuramente richiede molta meno memoria.

Certo, sarà ancora più lento di un semplice vecchio ciclo for, e se hai davvero bisogno di prestazioni, dovresti usare

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

Benchmark utilizzando MiniBench :

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];
    }
}

Risultati (nome, numero di iterazioni, durata totale, punteggio (il punteggio più alto è negativo)):

============ 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

Quale sarebbe un esempio di argomento di tipo generico che passeresti a BitArray<T> se esistesse?

BitArray è definito come:

  

Gestisce un array compatto di valori di bit,   che sono rappresentati come booleani,   dove true indica che il bit è   on (1) e false indica che il bit è   off (0).

Questo tipo è un array ottimizzato di bit, nient'altro. Non ha alcun valore renderlo generico in quanto non vi sono nessun membro che potrebbe essere considerato fuori dal tipo. Qualsiasi raccolta specializzata come questa può essere considerata come un tipo costruito chiuso di una raccolta generica padre. In altre parole, List<Boolean> è un po 'come IEnumerable (con molti metodi utili aggiunti ovviamente).

Modifica: Sì, questo tipo implementa IEnumerable<T> e non implementa Enumerable.Cast<TResult> - questo è molto probabilmente dovuto al fatto che è un tipo precedente e non è stato aggiornato. Ricorda che puoi utilizzare <=> per aggirare questo problema :

yourBitArray.Cast<bool>();

Quale possibile motivo avresti per una versione generica? Che tipo di bitArray potrebbe usare accanto a bit o booleani che vengono trasformati in bit a seconda dei casi?

Aggiornamento: È sicuro. Se stai eseguendo un foreach (var bit in bitArray), allora bit apparirà come un oggetto, ma puoi fare altrettanto facilmente foreach (bool bit in bitArray), questo accade per tutte le raccolte che implementano IEnumerable e non IEnumerable<T>.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top