Если вы можете получить массив int, лежащий в основе BitArray, это должно обеспечить гораздо лучшую производительность:
Предполагая, что вы не знаете, сколько битов установлено:
public static int[] GetIndexesForPositives()
{
var idIndexes = new List<int>();
System.Reflection.FieldInfo field = data.GetType().GetField("m_array", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
int[] values = field.GetValue(data) as int[];
for (var i = 0; i < values.Length; i++)
{
int _i = values[i];
if (_i != 0)
{
for (var j = 0; j < 32; j++)
{
if ((_i & (1 << j)) != 0)
{
idIndexes.Add(i * 32 + j);
}
}
}
}
return idIndexes.ToArray();
}
Если вы знаете количество установленных битов, вы можете сделать это вместо:
public static int[] GetIndexesForPositives(int length)
{
var idIndexes = new int[length];
var idx = 0;
System.Reflection.FieldInfo field = data.GetType().GetField("m_array", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
int[] values = field.GetValue(data) as int[];
for (var i = 0; i < values.Length; i++)
{
int _i = values[i];
if (_i != 0)
{
for (var j = 0; j < 32; j++)
{
if ((_i & (1 << j)) != 0)
{
idIndexes[idx++] = i * 32 + j;
}
}
}
}
В моих тестах эти два теста работают быстрее, чем ваш метод, даже тот, который не знает, насколько большим будет возвращаемый массив.
Мои результаты проверены с использованием случайного BitArray из 50 миллионов записей:
1) 25001063 records found in 50000000, took 1415.5752ms
2) 25001063 records found in 50000000, took 1099.67ms
3) 25001063 records found in 50000000, took 1045.6862ms
4) 25001063 records found in 50000000, took 745.7762ms"
1) is your code but using an arraylist instead of using some `GetPositiveCount` to get the output length.
2) is your code
3) is my (revised) first example
4) is my (revised) second example
edit: более того, стоит отметить, что это проблема, которая может действительно выиграть от многопоточности. Разбейте ByteArray на 4 части, и у вас будет 4 потока, которые могут запустить проверку данных сразу.
Редактировать: я знаю, что это уже принято, но вот еще один шаг, который вы можете сделать, чтобы улучшить производительность, если вы знаете, что большую часть времени ваш список будет очень скудным:
for (var j = 0; j < 32; j++)
{
if (_i == 0)
break;
if ((_i & (1)) != 0)
{
idIndexes.Add(i * 32 + j);
}
_i = _i >> 1;
}
это немного медленнее, если список заполнен> 40% или более, однако, если вы знаете, что список всегда будет 10% 1 с и 90% 0, то это будет работать еще быстрее для вас.