3

我的要求很简单:

  1. 能够定义位数组的维度,即:5字节。
  2. 布尔获取(位索引:int)
  3. 设置(位索引:int)

是否有 ac# 等效项提供与BitSetJava 中类似的功能?

这是场景:

  1. 初始化 5 个字节,所有位为 0(假)。
  2. 将字节 3、位 8 设置为 TRUE。
  3. 获取字节 3、位 8 的状态。

更新:Michael Bray 的解决方案:

static void Main(string[] args) 
{ 
  // Set for 5 bytes 
  BitArray ba = new BitArray(8 * 5); 

  // Set bit #1 on byte #4 
  ba.Set(GetBitNum(4, 1), true); 

  // Get bit #1 on byte #4 
  bool v = ba.Get(GetBitNum(4, 1)); 
} 

static int GetBitNum(int byteNum, int bitNum)   // Assumes index starts at 1 
{ 
  return (byteNum - 1) * 8 + (bitNum - 1); 
}
4

2 回答 2

8

System.Collections.BitArray非常接近,但它有点缺乏功能。不久前,我编写了一个帮助类,它实现了 BitArray 可能需要的许多功能,但我必须对其进行挖掘。如果你认为你需要它,请告诉我。

编辑:按照下面评论中的要求,我已在http://pastebin.com/GLyzcUZC上发布了代码。不过,正如我所讨论的,它相对于库存 BitArray 的好处是微乎其微的,因为我写它是为了满足我的一些特定需求。随心所欲地使用它。

编辑 2:正如 Miguel 在评论中指出的那样,有一些实现问题使我的“BitArray”代码不太好......我已经意识到了这些缺陷并重新编写了一个名为 BoolArray 的新版本(以区别于 BitArray ) 不会受到这些问题的影响:

namespace Utils
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Threading;

    /// <summary>
    /// A replacement for BitArray
    /// </summary>
    public class BoolArray : IEnumerable, ICollection, ICloneable
    {
        private UInt32[] bits = null;
        private int _length = 0;
        private static UInt32 ONE = (UInt32)1 << 31;
        private object _syncRoot;
        private static Func<byte[], byte[]> EndianFixer = null;

        #region Constructors

        static BoolArray()
        {
            if (BitConverter.IsLittleEndian) EndianFixer = (a) => a.Reverse().ToArray();
            else EndianFixer = (a) => a;
        }

        public BoolArray(BoolArray srcBits)
        {
            this.InitializeFrom(srcBits.ToArray());
        }

        public BoolArray(BitArray srcBits)
        {
            this._length = srcBits.Count;
            this.bits = new UInt32[RequiredSize(this._length)];

            for (int i = 0; i < srcBits.Count; i++) this[i] = srcBits[i];
        }

        public BoolArray(int v)
        {
            ICollection<byte> bytes = EndianFixer(BitConverter.GetBytes(v)).ToList();
            InitializeFrom(bytes);
        }

        public BoolArray(ICollection<bool> srcBits)
        {
            this.InitializeFrom(srcBits.ToArray());
        }

        public BoolArray(ICollection<byte> srcBits)
        {
            InitializeFrom(srcBits);
        }

        public BoolArray(ICollection<short> srcBits)
        {
            ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
            InitializeFrom(bytes);
        }

        public BoolArray(ICollection<ushort> srcBits)
        {
            ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
            InitializeFrom(bytes);
        }

        public BoolArray(ICollection<int> srcBits)
        {
            ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
            InitializeFrom(bytes);
        }

        public BoolArray(ICollection<uint> srcBits)
        {
            ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
            InitializeFrom(bytes);
        }

        public BoolArray(ICollection<long> srcBits)
        {
            ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
            InitializeFrom(bytes);
        }

        public BoolArray(ICollection<ulong> srcBits)
        {
            ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
            InitializeFrom(bytes);
        }

        public BoolArray(int capacity, bool defaultValue = false)
        {
            this.bits = new UInt32[RequiredSize(capacity)];
            this._length = capacity;

            // Only need to do this if true, because default for all bits is false
            if (defaultValue) for (int i = 0; i < this._length; i++) this[i] = true;
        }

        private void InitializeFrom(ICollection<byte> srcBits)
        {
            this._length = srcBits.Count * 8;
            this.bits = new UInt32[RequiredSize(this._length)];
            for (int i = 0; i < srcBits.Count; i++)
            {
                uint bv = srcBits.Skip(i).Take(1).Single();
                for (int b = 0; b < 8; b++)
                {
                    bool bitVal = ((bv << b) & 0x0080) != 0;
                    int bi = 8 * i + b;
                    this[bi] = bitVal;
                }
            }
        }

        private void InitializeFrom(ICollection<bool> srcBits)
        {
            this._length = srcBits.Count;
            this.bits = new UInt32[RequiredSize(this._length)];

            int index = 0;
            foreach (var b in srcBits) this[index++] = b;
        }

        private static int RequiredSize(int bitCapacity)
        {
            return (bitCapacity + 31) >> 5;
        }

        #endregion

        public bool this[int index]
        {
            get
            {
                if (index >= _length) throw new IndexOutOfRangeException();

                int byteIndex = index >> 5;
                int bitIndex = index & 0x1f;
                return ((bits[byteIndex] << bitIndex) & ONE) != 0;
            }
            set
            {
                if (index >= _length) throw new IndexOutOfRangeException();

                int byteIndex = index >> 5;
                int bitIndex = index & 0x1f;
                if (value) bits[byteIndex] |= (ONE >> bitIndex);
                else bits[byteIndex] &= ~(ONE >> bitIndex);
            }
        }

        #region Interfaces implementation
        #region IEnumerable
        public IEnumerator GetEnumerator()
        {
            //for (int i = 0; i < _length; i++) yield return this[i];
            return this.ToArray().GetEnumerator();
        }
        #endregion
        #region ICollection
        public void CopyTo(Array array, int index)
        {
            if (array == null) throw new ArgumentNullException("array");
            if (index < 0) throw new ArgumentOutOfRangeException("index");
            if (array.Rank != 1) throw new ArgumentException("Multidimensional array not supported");
            if (array is UInt32[]) Array.Copy(this.bits, 0, array, index, (this.Count + sizeof(UInt32) - 1) / sizeof(UInt32));
            else if (array is bool[]) Array.Copy(this.ToArray(), 0, array, index, this.Count);
            else throw new ArgumentException("Array type not supported (UInt32[] or bool[] only)");

        }

        public int Count
        {
            get { return this._length; }
            private set
            {
                if (value > this._length) Extend(value - this._length);
                else this._length = Math.Max(0, value);
            }
        }

        public bool IsSynchronized
        {
            get { return false; }
        }

        public object SyncRoot
        {
            get
            {
                if (this._syncRoot == null) Interlocked.CompareExchange<object>(ref this._syncRoot, new object(), null);
                return _syncRoot;
            }
        }
        #endregion
        #region ICloneable
        public object Clone()
        {
            return new BoolArray(this);
        }
        // Not part of ICloneable, but better - returns a strongly-typed result
        public BoolArray Dup()
        {
            return new BoolArray(this);
        }
        #endregion 
        #endregion

        #region String Conversions

        public override string ToString()
        {
            return ToBinaryString();
            //return ToHexString(" ", " ■ ");
        }

        public static BoolArray FromHexString(string hex)
        {
            if (hex == null) throw new ArgumentNullException("hex");

            List<bool> bits = new List<bool>();
            for (int i = 0; i < hex.Length; i++)
            {
                int b = byte.Parse(hex[i].ToString(), NumberStyles.HexNumber);
                bits.Add((b >> 3) == 1);
                bits.Add(((b & 0x7) >> 2) == 1);
                bits.Add(((b & 0x3) >> 1) == 1);
                bits.Add((b & 0x1) == 1);
            }
            BoolArray ba = new BoolArray(bits.ToArray());
            return ba;
        }

        public string ToHexString(string bitSep8 = null, string bitSep128 = null)
        {
            string s = string.Empty;
            int b = 0;
            bool[] bbits = this.ToArray();

            for (int i = 1; i <= bbits.Length; i++)
            {
                b = (b << 1) | (bbits[i - 1] ? 1 : 0);
                if (i % 4 == 0)
                {
                    s = s + string.Format("{0:x}", b);
                    b = 0;
                }

                if (i % (8 * 16) == 0)
                {
                    s = s + bitSep128;
                }
                else if (i % 8 == 0)
                {
                    s = s + bitSep8;
                }
            }
            int ebits = bbits.Length % 4;
            if (ebits != 0)
            {
                b = b << (4 - ebits);
                s = s + string.Format("{0:x}", b);
            }
            return s;
        }

        public static BoolArray FromBinaryString(string bin, char[] trueChars = null)
        {
            if (trueChars == null) trueChars = new char[] { '1', 'Y', 'y', 'T', 't' };
            if (bin == null) throw new ArgumentNullException("bin");
            BoolArray ba = new BoolArray(bin.Length);
            for (int i = 0; i < bin.Length; i++) ba[i] = bin[i].In(trueChars);
            return ba;
        }

        public string ToBinaryString(char setChar = '1', char unsetChar = '0')
        {
            return new string(this.ToArray().Select(v => v ? setChar : unsetChar).ToArray());
        }

        #endregion

        #region Class Methods
        public bool[] ToArray()
        {
            bool[] vbits = new bool[this._length];
            for (int i = 0; i < _length; i++) vbits[i] = this[i];
            return vbits;
        }

        public BoolArray Append(ICollection<bool> addBits)
        {
            int startPos = this._length;
            Extend(addBits.Count);
            bool[] bitArray = addBits.ToArray();
            for (int i = 0; i < bitArray.Length; i++) this[i + startPos] = bitArray[i];
            return this;
        }

        public BoolArray Append(BoolArray addBits)
        {
            return this.Append(addBits.ToArray());
        }

        public static BoolArray Concatenate(params BoolArray[] bArrays)
        {
            return new BoolArray(bArrays.SelectMany(ba => ba.ToArray()).ToArray());
        }

        private void Extend(int numBits)
        {
            numBits += this._length;
            int reqBytes = RequiredSize(numBits);
            if (reqBytes > this.bits.Length)
            {
                UInt32[] newBits = new UInt32[reqBytes];
                this.bits.CopyTo(newBits, 0);
                this.bits = newBits;
            }
            this._length = numBits;
        }

        public bool Get(int index)
        {
            return this[index];
        }

        public BoolArray GetBits(int startBit = 0, int numBits = -1)
        {
            if (numBits == -1) numBits = bits.Length;
            return new BoolArray(this.ToArray().Skip(startBit).Take(numBits).ToArray());
        }

        public BoolArray Repeat(int numReps)
        {
            bool[] oBits = this.ToArray();
            List<bool> nBits = new List<bool>();
            for(int i=0; i<numReps; i++) nBits.AddRange(oBits);
            this.InitializeFrom(nBits);
            return this;
        }

        public BoolArray Reverse()
        {
            int n = this.Count;
            for(int i=0; i<n/2; i++) 
            {
                bool b1 = this[i];
                this[i] = this[n - i - 1];
                this[n - i - 1] = b1;
            }
            return this;
        }

        public BoolArray Set(int index, bool v)
        {
            this[index] = v;
            return this;
        }

        public BoolArray SetAll(bool v)
        {
            for (int i = 0; i < this.Count; i++) this[i] = v;
            return this;
        }

        public BoolArray SetBits(ICollection<bool> setBits, int destStartBit = 0, int srcStartBit = 0, int numBits = -1, bool allowExtend = false)
        {
            if (setBits == null) throw new ArgumentNullException("setBits");
            if ((destStartBit < 0) || (destStartBit >= this.Count)) throw new ArgumentOutOfRangeException("destStartBit");
            if ((srcStartBit < 0) || (srcStartBit >= setBits.Count)) throw new ArgumentOutOfRangeException("srcStartBit");

            bool[] sBits;
            if (setBits is bool[]) sBits = (bool[])setBits;
            else sBits = setBits.ToArray();

            if (numBits == -1) numBits = setBits.Count;
            if (numBits > (setBits.Count - srcStartBit)) numBits = setBits.Count - srcStartBit;

            int diffSize = numBits - (this.Count - destStartBit);
            if (diffSize > 0)
            {
                if (allowExtend) Extend(diffSize);
                else numBits = this.Count - destStartBit;
            }
            for (int i = 0; i < numBits; i++) this[destStartBit + i] = sBits[srcStartBit + i];
            return this;
        }

        public List<BoolArray> SplitEvery(int numBits)
        {
            int i = 0;
            List<BoolArray> bitSplits = new List<BoolArray>();
            while (i < this.Count)
            {
                bitSplits.Add(this.GetBits(i, numBits));
                i += numBits;
            }
            return bitSplits;
        }

        public byte[] ToBytes(int startBit = 0, int numBits = -1)
        {
            if (numBits == -1) numBits = this._length - startBit;
            BoolArray ba = GetBits(startBit, numBits);
            int nb = (numBits + 7) / 8;
            byte[] bb = new byte[nb];
            for (int i = 0; i < ba.Count; i++)
            {
                if (!ba[i]) continue;
                int bp = 7 - (i % 8);
                bb[i / 8] = (byte)((int)bb[i / 8] | (1 << bp));
            }
            return bb;
        }


        #endregion

        #region Logical Bitwise Operations
        public BoolArray BinaryBitwiseOp(Func<bool, bool, bool> op, BoolArray ba, int start = 0)
        {
            for (int i = 0; i < ba.Count; i++)
            {
                if (start + i >= this.Count) break;
                this[start + i] = op(this[start + i], ba[i]);
            }
            return this;
        }

        public BoolArray Xor(BoolArray xor, int start = 0)
        {
            return BinaryBitwiseOp((a, b) => (a ^ b), xor, start);
        }

        public BoolArray And(BoolArray and, int start = 0)
        {
            return BinaryBitwiseOp((a, b) => (a & b), and, start);
        }

        public BoolArray Or(BoolArray or, int start = 0)
        {
            return BinaryBitwiseOp((a, b) => (a | b), or, start);
        }

        public BoolArray Not(int start = 0, int len = -1)
        {
            for (int i = start; i < this.Count; i++)
            {
                if (--len == -1) break;
                this[i] = !this[i];
            }
            return this;
        } 
        #endregion

        #region Class Operators

        public static BoolArray operator +(BoolArray a, BoolArray b)
        {
            return a.Dup().Append(b);
        }

        public static BoolArray operator |(BoolArray a, BoolArray b)
        {
            return a.Dup().Or(b);
        }

        public static BoolArray operator &(BoolArray a, BoolArray b)
        {
            return a.Dup().And(b);
        }

        public static BoolArray operator ^(BoolArray a, BoolArray b)
        {
            return a.Dup().Xor(b);
        }

        public static BoolArray operator ~(BoolArray a)
        {
            return a.Dup().Not();
        }

        public static BoolArray operator <<(BoolArray a, int shift)
        {
            return a.Dup().Append(new bool[shift]);
        }

        public static BoolArray operator >>(BoolArray a, int shift)
        {
            return new BoolArray(a.ToArray().Take(Math.Max(0, a.Count - shift)).ToArray());
        }

        public static bool operator ==(BoolArray a, BoolArray b)
        {
            if (a.Count != b.Count) return false;
            for (int i = 0; i < a.Count; i++) if (a[i] != b[i]) return false;
            return true;
        }
        public override bool Equals(object obj)
        {
            if (!(obj is BoolArray)) return false;
            return (this == (BoolArray)obj);
        }
        public override int GetHashCode()
        {
            return this.ToHexString().GetHashCode();
        }

        public static bool operator !=(BoolArray a, BoolArray b)
        {
            return !(a == b);
        }

        #endregion
    }
}
于 2012-12-26T03:30:07.723 回答
2

我有同样的问题,但不仅仅是一种基数方法来转换。所以,我选择移植整个 BitSet 类。幸好它是独立的。

这是C# 端口的要点

我还将它添加到开源BoboBrowse.Net 项目中。

我还从 Apache Harmony(本质上是 JDK 的抄本)移植了该版本,并将其添加到通用库J2N 中,因此易于使用。

于 2014-12-03T05:06:12.463 回答