4

.NET にジェネリック BitArray はありますか? 非ジェネリックのものしか見つかりませんでした。

一般的な BitArray はありますか? (つまり、合理的でしょうか?)


編集:

ジェネリックではなくタイプセーフと言うべきだったのかもしれません。

基本的に、タイプを として列挙するとき、それは orobjectであってはなりませんintbool? それとも、別のメンバー列挙子で提供されているものですか?


例:

foreach (bool bit in myBitArray)
{

}

編集:

BitArrayクラスの列挙子を確認したところ、すべてがobjectexcept.Currentプロパティを返します。

public virtual object Current
4

5 に答える 5

9

BitArray は、NET 1.x 時代の特殊なコレクション クラスです。ba.Set(int, bool)indexer プロパティを使用している限り、タイプ セーフです。

「タイプセーフではない」のは列挙です。BitArray は IEnumerable を実装しますが、IEnumerable< bool> は実装しません。したがって、ジョアンは正しいです。使用foreach()には、オブジェクトからブールへのキャストが含まれます。

しかし、それは本当の問題ですか?BitArray の要素はブール値であり、それらの位置と組み合わせた場合にのみ意味があります。BitArray にはAdd()メソッドがなく、Set(i, true).

foreach()したがって、簡単な答えは次のとおりです。IEnumerableに基づいた、またはその他のものは使用しないでください。ほとんど役に立たない真/偽の値のストリームを生成するだけです。

次のスニペットでは、BitArray は完全にタイプ セーフで効率的です。

BitArray isEven = ...;
for(int i = 0; i < isEven.Count; i++) 
{
   isEven.Set(i, i % 2 == 0);
}
于 2009-07-31T20:23:04.733 に答える
8

いいえ、ありません。

BitArray が存在する場合、そのどの部分がジェネリックになるかさえわかりません。

BitArrayを受け取ってを返す拡張メソッドを作成したり、 でループを使用しbool[]たり するのは難しくありません。のインデクサーを使用するため、ループはボクシングを必要としません。また、ボクシングせずに を列挙することもできます。List<bool>forBitArrayforBitArraybool[] List<bool>

拡張方法の例:

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

簡単なベンチマークからわかったのは (好奇心が私を圧倒した)、foreach (bool b in myBitArray.ToList())75% から 85% の時間でforeach (bool b in myBitArray). それは毎回リストを作成します。リストを 1 回作成し、それを何度も繰り返すのに、foreach (bool b in myBitArray)かかった時間の 20% から 25% かかりました。bool値を複数回反復する必要があり、呼び出した時点から変更されていないことがわかっmyBitArray.ToList()ている場合にのみ、それを利用できます。

foreach (bool b in Enumerable.Cast<bool(myBitArray))かかった時間の 150%foreach (bool b in myBitArray)かかりました。

さらに別の編集:これはゲームなので、たとえそれがあなた自身のBitArray. クラスが封印されているため (機能を継承して追加することはできません)、時間を節約し、Reflectorを使用してstudyのコードのほとんどをコピーできます。BitArray

編集:リフレクターからコードをコピーするという提案を打ちました。イテレータやクロージャなど、直接コピーしたくない奇妙なコードが生成されるものがあります。

于 2009-07-31T18:06:43.027 に答える
7

BitArrayボクシングしたり、次のように変換したりせずに反復できますList<bool>

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

これは、リストに変換するよりも高速であり、メモリの消費量も確実に少なくなります。

もちろん、それでも単純な古いforループよりも遅くなります。本当にパフォーマンスが必要な場合は、

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

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

結果 (名前、反復回数、合計期間、スコア (高スコアは悪い)):

============ 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
于 2009-08-03T13:58:12.597 に答える
2

存在する場合に渡すジェネリック型引数の例は何BitArray<T>ですか?

BitArrayと定義されている:

ブール値として表されるビット値のコンパクトな配列を管理します。true はビットがオン (1) であることを示し、false はビットがオフ (0) であることを示します。

この型はビットの最適化された配列であり、他には何もありません。型から分解できるメンバーがないため、ジェネリックにする価値はありません。このような特殊なコレクションは、親のジェネリック コレクションの閉じた構築型と見なすことができます。言い換えれば、(もちろん多くの便利なメソッドが追加されています)BitArrayのようなものです。List<Boolean>

編集: はい、この型は実装されIEnumerableていますが、実装されていませんIEnumerable<T>。これは、古い型であり、更新されていないことが原因である可能性が最も高いです。Enumerable.Cast<TResult>この問題を回避するために使用できることを覚えておいてください。

yourBitArray.Cast<bool>();
于 2009-07-31T18:07:20.060 に答える
1

ジェネリック バージョンの理由として考えられるものは何ですか? BitArray は、ビット、または場合によってはビットに変換されるブール値のほかに、どの型を使用できるでしょうか?

更新: タイプセーフです。foreach(var bit in bitArray) を実行している場合、bit はオブジェクトとして表示されますが、foreach(bool bit in bitArray) も同様に簡単に実行できます。これは、IEnumerable を実装し、実装していないすべてのコレクションで発生します。IEnumerable<T>.

于 2009-07-31T18:07:58.233 に答える