13

*ここでの「効率的」とは、基本的にサイズが小さい (IO 待機時間を短縮する) ことと、取得/デシリアライズ時間が速いことを意味します。保存時間はそれほど重要ではありません。

それぞれが 0 から 50 の範囲の 1800 個の値を持つ数十個の整数の配列を、ブラウザーの localStorage に、つまり文字列として格納する必要があります。

明らかに、最も簡単な方法はJSON.stringify、データの範囲がよく知られていることを考えると、多くの不要な情報を追加することです。これらの配列の 1 つの平均サイズは、約 5500 バイトです。

ここに私が試したいくつかの他の方法があります(結果のサイズ、および最後に1000回逆シリアル化する時間)

  • 数字をゼロで埋めて、それぞれが 2 文字の長さになるようにします。例:

    [5, 27, 7, 38] ==> "05270738"
    
  • base 50 エンコード:

    [5, 11, 7, 38] ==> "5b7C"
    
  • 値を文字コードとして使用するだけです(最初に奇妙な制御文字を避けるために32を追加します):

    [5, 11, 7, 38] ==> "%+'F" (String.fromCharCode(37), String.fromCharCode(43) ...)
    

ここに私の結果があります:

                  size     Chrome 18   Firefox 11
-------------------------------------------------
JSON.stringify    5286          60ms         99ms
zero-padded       3600         354ms        703ms
base 50           1800         315ms        400ms
charCodes         1800          21ms        178ms

私の質問は、まだ検討していないさらに良い方法があるかどうかです。


MДΓΓБДLL を更新すると、データの圧縮を使用することが提案されました。この LZW 実装を base 50 および charCode データと組み合わせます。また、aroth のコード (4 つの整数を 3 バイトにパックする) もテストしました。私はこれらの結果を得ました:

                  size     Chrome 18   Firefox 11
-------------------------------------------------
LZW base 50       1103         494ms        999ms
LZW charCodes     1103         194ms        882ms
bitpacking        1350        2395ms        331ms
4

3 に答える 3

4

範囲が 0 ~ 50 の場合、4 つの数値を 3 バイト (数値あたり 6 ビット) にパックできます。これにより、最大 1350 バイトを使用して 1800 個の数値を格納できます。このコードはそれを行う必要があります:

window._firstChar = 48;

window.decodeArray = function(encodedText) {
    var result = [];
    var temp = [];

    for (var index = 0; index < encodedText.length; index += 3) {
        //skipping bounds checking because the encoded text is assumed to be valid
        var firstChar = encodedText.charAt(index).charCodeAt() - _firstChar;
        var secondChar = encodedText.charAt(index + 1).charCodeAt() - _firstChar;
        var thirdChar = encodedText.charAt(index + 2).charCodeAt() - _firstChar;

        temp.push((firstChar >> 2) & 0x3F);    //6 bits, 'a'
        temp.push(((firstChar & 0x03) << 4) | ((secondChar >> 4) & 0xF));  //2 bits + 4 bits, 'b'
        temp.push(((secondChar & 0x0F) << 2) | ((thirdChar >> 6) & 0x3));  //4 bits + 2 bits, 'c'
        temp.push(thirdChar & 0x3F);  //6 bits, 'd'

    }

    //filter out 'padding' numbers, if present; this is an extremely inefficient way to do it
    for (var index = 0; index < temp.length; index++) {
        if(temp[index] != 63) {
            result.push(temp[index]);
        }            
    }

    return result;
};

window.encodeArray = function(array) {
    var encodedData = [];

    for (var index = 0; index < dataSet.length; index += 4) {
        var num1 = dataSet[index];
        var num2 = index + 1 < dataSet.length ? dataSet[index + 1] : 63;
        var num3 = index + 2 < dataSet.length ? dataSet[index + 2] : 63;
        var num4 = index + 3 < dataSet.length ? dataSet[index + 3] : 63;

        encodeSet(num1, num2, num3, num4, encodedData);
    }

    return encodedData;
};

window.encodeSet = function(a, b, c, d, outArray) {
    //we can encode 4 numbers in 3 bytes
    var firstChar = ((a & 0x3F) << 2) | ((b >> 4) & 0x03);   //6 bits for 'a', 2 from 'b'
    var secondChar = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F);  //remaining 4 bits from 'b', 4 from 'c'
    var thirdChar = ((c & 0x03) << 6) | (d & 0x3F);          //remaining 2 bits from 'c', 6 bits for 'd'

    //add _firstChar so that all values map to a printable character
    outArray.push(String.fromCharCode(firstChar + _firstChar));
    outArray.push(String.fromCharCode(secondChar + _firstChar));
    outArray.push(String.fromCharCode(thirdChar + _firstChar));
};

簡単な例を次に示します: http://jsfiddle.net/NWyBx/1

結果の文字列に gzip 圧縮を適用することで、ストレージ サイズをさらに削減できる可能性があることに注意してください。

または、数値の順序が重要でない場合は、51 個のバケットを使用してバケット ソートを実行し (0 ~ 50 には有効な数値として 0 と 50 の両方が含まれると仮定)、数値自体の代わりに各バケットのカウントを格納することができます。 . これにより、他のどのアプローチよりも優れた圧縮と効率が得られる可能性があります。

于 2012-04-12T01:01:22.837 に答える
0

(テストのように)圧縮にサイズの縮小よりも時間がかかると仮定すると、文字エンコードはビットシフトなしで取得できる最小のものです。現在、各数値に1バイトを使用していますが、十分に小さいことが保証されている場合は、各バイトに2つの数値を入れることができます。これがあなたのコードの非常にホットな部分でない限り、それはおそらく過度に最適化されるでしょう。

于 2012-04-12T00:32:07.423 に答える
0

Uint8Arrayまたはの使用を検討してArrayBufferください。このブログ投稿は、その方法を示しています。Uint8Array彼のロジックをコピーすると、既存のnamedがあると仮定して、例を次に示しますarr

function arrayBufferToBinaryString(buffer, cb) {
    var blobBuilder = new BlobBuilder();
    blobBuilder.append(buffer);
    var blob = blobBuilder.getBlob();
    var reader = new FileReader();
    reader.onload = function (e) {
        cb(reader.result);
    };
    reader.readAsBinaryString(blob);
}
arrayBufferToBinaryString(arr.buffer, function(s) { 
  // do something with s
});
于 2012-04-12T00:52:49.103 に答える