You can iterate BitArray
without boxing or converting it to List<bool>
:
public static IEnumerable<bool> GetTypeSafeEnumerator(this BitArray ba) {
for (int i = 0; i < ba.Length; i++)
yield return ba[i];
}
This should be faster than converting to list and certainly take much less memory.
Of course, it is still going to be slower than a plain old for
loop, and if you really need performance, you should use
for (int i = 0; i < ba.Length; i++) {
bool b = ba[i];
...
}
Benchmark using 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];
}
}
Results (name, number of iterations, total duration, score (high score is bad)):
============ 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