How do I create bit array in Javascript?

后端 未结 8 709
别跟我提以往
别跟我提以往 2020-12-05 04:47

What is the best way of implementing a bit array in JavaScript?

相关标签:
8条回答
  • 2020-12-05 05:23

    I don't know about bit arrays, but you can make byte arrays easy with new features.

    Look up typed arrays. I've used these in both Chrome and Firefox. The important one is Uint8Array.

    To make an array of 512 uninitialized bytes:

    var arr = new UintArray(512);
    

    And accessing it (the sixth byte):

    var byte = arr[5];
    

    For node.js, use Buffer (server-side).

    EDIT:

    To access individual bits, use bit masks.

    To get the bit in the one's position, do num & 0x1

    0 讨论(0)
  • 2020-12-05 05:27

    Here's one I whipped up:

    UPDATE - something about this class had been bothering me all day - it wasn't size based - creating a BitArray with N slots/bits was a two step operation - instantiate, resize. Updated the class to be size based with an optional second paramter for populating the size based instance with either array values or a base 10 numeric value.

    (Fiddle with it here)

    /* BitArray DataType */
    
    // Constructor
    function BitArray(size, bits) {
        // Private field - array for our bits
        this.m_bits = new Array();
    
        //.ctor - initialize as a copy of an array of true/false or from a numeric value
        if (bits && bits.length) {
            for (var i = 0; i < bits.length; i++)
                this.m_bits.push(bits[i] ? BitArray._ON : BitArray._OFF);
        } else if (!isNaN(bits)) {
            this.m_bits = BitArray.shred(bits).m_bits;
    
        }
        if (size && this.m_bits.length != size) {
            if (this.m_bits.length < size) {
                for (var i = this.m_bits.length; i < size; i++) {
                    this.m_bits.push(BitArray._OFF);
                }
            } else {
                for(var i = size; i > this.m_bits.length; i--){
                    this.m_bits.pop();
                }
            }
        }
    }
    
    /* BitArray PUBLIC INSTANCE METHODS */
    
    // read-only property - number of bits 
    BitArray.prototype.getLength = function () { return this.m_bits.length; };
    
    // accessor - get bit at index 
    BitArray.prototype.getAt = function (index) {
        if (index < this.m_bits.length) {
            return this.m_bits[index];
        }
        return null;
    };
    // accessor - set bit at index 
    BitArray.prototype.setAt = function (index, value) {
        if (index < this.m_bits.length) {
            this.m_bits[index] = value ? BitArray._ON : BitArray._OFF;
        }
    };
    
    // resize the bit array (append new false/0 indexes) 
    BitArray.prototype.resize = function (newSize) {
        var tmp = new Array();
        for (var i = 0; i < newSize; i++) {
            if (i < this.m_bits.length) {
                tmp.push(this.m_bits[i]);
            } else {
                tmp.push(BitArray._OFF);
            }
        }
        this.m_bits = tmp;
    };
    
    // Get the complimentary bit array (i.e., 01 compliments 10)
    BitArray.prototype.getCompliment = function () {
        var result = new BitArray(this.m_bits.length);
        for (var i = 0; i < this.m_bits.length; i++) {
            result.setAt(i, this.m_bits[i] ? BitArray._OFF : BitArray._ON);
        }
        return result;
    };
    
    // Get the string representation ("101010") 
    BitArray.prototype.toString = function () {
        var s = new String();
        for (var i = 0; i < this.m_bits.length; i++) {
            s = s.concat(this.m_bits[i] === BitArray._ON ? "1" : "0");
        }
        return s;
    };
    
    // Get the numeric value 
    BitArray.prototype.toNumber = function () {
        var pow = 0;
        var n = 0;
        for (var i = this.m_bits.length - 1; i >= 0; i--) {
            if (this.m_bits[i] === BitArray._ON) {
                n += Math.pow(2, pow);
            }
            pow++;
        }
        return n;
    };
    
    /* STATIC METHODS */
    
    // Get the union of two bit arrays
    BitArray.getUnion = function (bitArray1, bitArray2) {
        var len = BitArray._getLen(bitArray1, bitArray2, true);
        var result = new BitArray(len);
        for (var i = 0; i < len; i++) {
            result.setAt(i, BitArray._union(bitArray1.getAt(i), bitArray2.getAt(i)));
        }
        return result;
    };
    
    // Get the intersection of two bit arrays 
    BitArray.getIntersection = function (bitArray1, bitArray2) {
        var len = BitArray._getLen(bitArray1, bitArray2, true);
        var result = new BitArray(len);
        for (var i = 0; i < len; i++) {
            result.setAt(i, BitArray._intersect(bitArray1.getAt(i), bitArray2.getAt(i)));
        }
        return result;
    };
    
    // Get the difference between to bit arrays
    BitArray.getDifference = function (bitArray1, bitArray2) {
        var len = BitArray._getLen(bitArray1, bitArray2, true);
        var result = new BitArray(len);
        for (var i = 0; i < len; i++) {
            result.setAt(i, BitArray._difference(bitArray1.getAt(i), bitArray2.getAt(i)));
        }
        return result;
    };
    
    // Convert a number into a bit array
    BitArray.shred = function (number) {
        var bits = new Array();
        var q = number;
        do {
            bits.push(q % 2);
            q = Math.floor(q / 2);
        } while (q > 0);
        return new BitArray(bits.length, bits.reverse());
    };
    
    /* BitArray PRIVATE STATIC CONSTANTS */
    BitArray._ON = 1;
    BitArray._OFF = 0;
    
    /* BitArray PRIVATE STATIC METHODS */
    
    // Calculate the intersection of two bits 
    BitArray._intersect = function (bit1, bit2) {
        return bit1 === BitArray._ON && bit2 === BitArray._ON ? BitArray._ON : BitArray._OFF;
    };
    
    // Calculate the union of two bits 
    BitArray._union = function (bit1, bit2) {
        return bit1 === BitArray._ON || bit2 === BitArray._ON ? BitArray._ON : BitArray._OFF;
    };
    
    // Calculate the difference of two bits 
    BitArray._difference = function (bit1, bit2) {
        return bit1 === BitArray._ON && bit2 !== BitArray._ON ? BitArray._ON : BitArray._OFF;
    };
    
    // Get the longest or shortest (smallest) length of the two bit arrays 
    BitArray._getLen = function (bitArray1, bitArray2, smallest) {
        var l1 = bitArray1.getLength();
        var l2 = bitArray2.getLength();
    
        return l1 > l2 ? smallest ? l2 : l1 : smallest ? l2 : l1;
    };
    

    CREDIT TO @Daniel Baulig for asking for the refactor from quick and dirty to prototype based.

    0 讨论(0)
  • 2020-12-05 05:38

    Something like this is as close as I can think of. Saves bit arrays as 32 bit numbers, and has a standard array backing it to handle larger sets.

    class bitArray {
      constructor(length) {
        this.backingArray = Array.from({length: Math.ceil(length/32)}, ()=>0)
        this.length = length
      }
      get(n) {
        return (this.backingArray[n/32|0] & 1 << n % 32) > 0
      }
      on(n) {
        this.backingArray[n/32|0] |= 1 << n % 32
      }
      off(n) {
        this.backingArray[n/32|0] &= ~(1 << n % 32)
      }
      toggle(n) {
        this.backingArray[n/32|0] ^= 1 << n % 32
      }
      forEach(callback) {
        this.backingArray.forEach((number, container)=>{
          const max = container == this.backingArray.length-1 ? this.length%32 : 32
          for(let x=0; x<max; x++) {
            callback((number & 1<<x)>0, 32*container+x)
          }
        })
      }
    }
    let bits = new bitArray(10)
    bits.get(2) //false
    bits.on(2)
    bits.get(2) //true
    
    bits.forEach(console.log) 
    /* outputs:
    false
    false
    true
    false
    false
    false
    false
    false
    false
    false
    */
    
    bits.toggle(2)
    
    bits.forEach(console.log) 
    /* outputs:
    false
    false
    false
    false
    false
    false
    false
    false
    false
    false
    */
    
    bits.toggle(0)
    bits.toggle(1)
    bits.toggle(2)
    
    bits.off(2)
    bits.off(3)
    bits.forEach(console.log) 
    /* outputs:
    true
    true
    false
    false
    false
    false
    false
    false
    false
    false
    */
    
    0 讨论(0)
  • 2020-12-05 05:38

    Thanks for a wonderfully simple class that does just what I need.

    I did find a couple of edge-case bugs while testing:

    get(n) {
        return (this.backingArray[n/32|0] & 1 << n % 32) != 0
        // test of > 0 fails for bit 31
    }
    
    forEach(callback) {
        this.backingArray.forEach((number, container)=>{
            const max = container == this.backingArray.length-1 && this.length%32
                ? this.length%32 : 32;
                // tricky edge-case: at length-1 when length%32 == 0,
                // need full 32 bits not 0 bits
        for(let x=0; x<max; x++) {
            callback((number & 1<<x)!=0, 32*container+x) // see fix in get()
        }
    })
    

    My final implementation fixed the above bugs and changed the backArray to be a Uint8Array instead of Array, which avoids signed int bugs.

    0 讨论(0)
  • 2020-12-05 05:42

    The Stanford Javascript Crypto Library (SJCL) provides a Bit Array implementation and can convert different inputs (Hex Strings, Byte Arrays, etc.) to Bit Arrays.

    Their code is public on GitHub: bitwiseshiftleft/sjcl. So if you lookup bitArray.js, you can find their bit array implementation.

    A conversion from bytes to bits can be found here.

    0 讨论(0)
  • 2020-12-05 05:43

    Probably [definitely] not the most efficient way to do this, but a string of zeros and ones can be parsed as a number as a base 2 number and converted into a hexadecimal number and finally a buffer.

    const bufferFromBinaryString = (binaryRepresentation = '01010101') =>
        Buffer.from(
            parseInt(binaryRepresentation, 2).toString(16), 'hex');
    

    Again, not efficient; but I like this approach because of the relative simplicity.

    0 讨论(0)
提交回复
热议问题