簡體   English   中英

如何在 Javascript 中創建位數組?

[英]How do I create bit array in Javascript?

在 JavaScript 中實現位數組的最佳方法是什么?

這是我掀起的一個:

更新 - 關於這個類的一些事情整天困擾着我 - 它不是基於大小的 - 創建一個帶有 N 個插槽/位的 BitArray 是一個兩步操作 - 實例化,調整大小。 將類更新為基於大小的可選第二個參數,用於使用數組值或基數為 10 的數值填充基於大小的實例。

在這里擺弄它)

/* 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;
};

感謝@Daniel Baulig 要求重構從快速和骯臟到基於原型。

我不了解位數組,但是您可以使用新功能使字節數組變得容易。

查找類型化數組 我在 Chrome 和 Firefox 中都使用過這些。 重要的是 Uint8Array。

要創建一個包含 512 個未初始化字節的數組:

var arr = new UintArray(512);

並訪問它(第六個字節):

var byte = arr[5];

對於 node.js,使用Buffer (服務器端)。

編輯:

要訪問單個位,請使用位掩碼。

要獲得一個位的位,請執行num & 0x1

像這樣的事情是我能想到的最接近的事情。 將位數組保存為 32 位數字,並有一個標准數組支持它來處理更大的集合。

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
*/

斯坦福 Javascript 加密庫 (SJCL)提供了位數組實現,可以將不同的輸入(十六進制字符串、字節數組等)轉換為位數組

他們的代碼在 GitHub 上是公開的: bitwiseshiftleft/sjcl 因此,如果您查找bitArray.js ,您可以找到它們的位數組實現。

可以在此處找到從字節到位的轉換。

您可以使用按位運算符輕松地做到這一點。 這很簡單。 讓我們試試數字 75。

它的二進制表示是 100 1011。那么,我們如何從數字中獲得每一位呢? 您可以使用 AND "&" 運算符來選擇一位並將其余的設置為 0。然后使用 Shift 運算符,您可以刪除目前無關緊要的 0 的其余部分。

例子:

Let's do an AND operation with 4 (000 0010)

0100 1011 & 0000 0010 => 0000 0010

現在我們需要過濾選定的位,在這種情況下,是從右到左讀取的第二位。

0000 0010 >> 1 => 1

左邊的零不代表。 所以輸出將是我們選擇的位,在這種情況下,是第二位。


var word=75;
var res=[];
for(var x=7; x>=0; x--){
  res.push((word&Math.pow(2,x))>>x);
}
console.log(res);

輸出:

在此處輸入圖片說明

預期的:

在此處輸入圖片說明

如果您需要的不僅僅是一個簡單的數字,您可以對一個字節應用相同的功能。 假設您有一個包含多個字節的文件。 因此,您可以將該文件分解為 ByteArray,然后將數組中的每個字節分解為 BitArray。

祝你好運!

@Commi 的實現是我最終使用的。

我相信這個實現中有一個錯誤。 每個第 31 個邊界上的位給出錯誤的結果。 (即當 index 為(32 * index - 1) ,則為 31、63、95 等。

我在 get() 方法中通過將> 0替換為!= 0修復它。

get(n) {
    return (this.backingArray[n/32|0] & 1 << n % 32) != 0
}

錯誤的原因是整數是 32 位有符號的。 將 1 左移 31 會得到一個負數。 由於檢查是針對>0 ,因此當它應該為真時將是假的。

我寫了一個程序來證明之前的錯誤,以及之后的修復。 將發布它的空間不足。

for (var i=0; i < 100; i++) {
  var ar = new bitArray(1000);
  
  ar.on(i);

  for(var j=0;j<1000;j++) {

    // we should have TRUE only at one position and that is "i". 
    // if something is true when it should be false or false when it should be true, then report it.

    if(ar.get(j)) {
      if (j != i) console.log('we got a bug at ' + i);
    } 

    if (!ar.get(j)) {
      if (j == i) console.log('we got a bug at ' + i);
    }
  }
}

可能 [絕對] 不是最有效的方法,但是一串零和一可以被解析為一個數字作為基數為 2 的數字並轉換為十六進制數,最后轉換為緩沖區。

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

同樣,效率不高; 但我喜歡這種方法,因為它相對簡單。

感謝您提供一個非常簡單的課程,它可以滿足我的需求。

我在測試時確實發現了一些邊緣情況的錯誤:

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()
    }
})

我的最終實現修復了上述錯誤並將 backArray 更改為 Uint8Array 而不是 Array,從而避免了簽名 int 錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM