我一直想知道在 C# 中反转 BitArray 顺序的最有效方法是什么。需要明确的是,我不想通过调用 .Not() 来反转 Bitarray,我想反转数组中位的顺序。
干杯,克里斯
public void Reverse(BitArray array)
{
int length = array.Length;
int mid = (length / 2);
for (int i = 0; i < mid; i++)
{
bool bit = array[i];
array[i] = array[length - i - 1];
array[length - i - 1] = bit;
}
}
对于长数组和相对较少的用途,只需将其包装:
class BitArrayReverse
{
private BitArray _ba;
public BitArrayReverse(BitArray ba) { _ba = ba; }
public bool this[int index]
{
get { return _ba[_ba.Length - 1 - index]; }
set { _ba[_ba.Length - 1 - index] = value; }
}
}
这将是在 for 循环中使用 XOR 反转任何长度的 MSB <-> LSB 的最佳方法
public static BitArray BitsReverse(BitArray bits)
{
int len = bits.Count;
BitArray a = new BitArray(bits);
BitArray b = new BitArray(bits);
for (int i = 0, j = len-1; i < len; ++i, --j)
{
a[i] = a[i] ^ b[j];
b[j] = a[i] ^ b[j];
a[i] = a[i] ^ b[j];
}
return a;
}
// in 010000011010000011100b
// out 001110000010110000010b
Dim myBA As New BitArray(4)
myBA(0) = True
myBA(1) = False
myBA(2) = True
myBA(3) = True
Dim myBoolArray1(3) As Boolean
myBA.CopyTo(myBoolArray1, 0)
Array.Reverse(myBoolArray1)
myBA = New BitArray(myBoolArray1)
因为如果将大小固定为 8 位,只需从下面进行“表”查找就足够了——在处理普通byte
的情况时,查找可能是最快的方法。但是,BitSet 获取/设置数据的额外开销可能会抵消查找的好处。还需要考虑初始构建成本和持久开销(但可以将值编码为数组文字...... ick!)
另一方面,如果数据只有8 位(曾经),并且“性能很重要”,为什么还要使用 BitArray?BitArray 始终可以用于很好的功能,例如“爆炸”到 Enumerable,而 C# 已经内置了不错的字节位操作。
假设数据是 8 位对齐的更一般的情况......但长度不确定
这实际上是否比仅在 BitArray 中“按项目”执行更好(更快、更高效等)?我不知道,但怀疑不是。我肯定会从“简单”的方法开始——这只是一个概念验证,在基准测试中比较可能(或可能不)有趣。无论如何,先写清楚......下面不是它!(其中至少有一个错误——我责怪额外的复杂性;-)
byte reverse (byte b) {
byte o = 0;
for (var i = 0; i < 8; i++) {
o <<= 1;
o |= (byte)(b & 1);
b >>= 1;
}
return o;
}
byte[] table;
BitArray reverse8 (BitArray ar) {
if (ar.Count % 8 != 0) {
throw new Exception("no!");
}
byte[] d = new byte[ar.Count / 8];
ar.CopyTo(d, 0);
// this only works if the bit array is
// a multiple of 8. we swap bytes and
// then reverse bits in each byte
int mid = d.Length / 2;
for (int i = 0, j = d.Length - 1; i < mid; i++, j--) {
byte t = d[i];
d[i] = table[d[j]];
d[j] = table[t];
}
return new BitArray(d);
}
string tostr (BitArray x) {
return string.Join("",
x.OfType<bool>().Select(i => i ? "1" : "0").ToArray());
}
void Main()
{
table = Enumerable.Range(0,256).Select(v => reverse((byte)v)).ToArray();
{
byte[] s = new byte[] { 1, 0xff };
BitArray ar = new BitArray(s);
// linqpad :)
tostr(ar).Dump();
tostr(reverse8(ar)).Dump();
}
"--".Dump();
{
byte[] s = new byte[] { 3, 42, 19 };
BitArray ar = new BitArray(s);
// linqpad :)
tostr(ar).Dump();
tostr(reverse8(ar)).Dump();
}
}
输出:
1000000011111111 1111111100000001 -- 110000000101010011001000 000100110101010000000011
这expr.Dump()
是一个LINQPad功能。
改编了@TimLoyd 的答案,并将其变成了一个扩展,以便于使用。
public static BitArray Reverse(this BitArray array)
{
int length = array.Length;
int mid = (length / 2);
for (int i = 0; i < mid; i++)
{
bool bit = array[i];
array[i] = array[length - i - 1];
array[length - i - 1] = bit;
}
return new BitArray(array);
}
用法:
var bits = new BitArray(some_bytes).Reverse();