*“高效”这里基本上意味着更小的尺寸(减少IO等待时间),以及快速的检索/反序列化时间。存储时间并不重要。
我必须在浏览器的localStorage中存储几十个整数数组,每个数组的数值范围为0-50,包括1800个值 - 也就是字符串。
显然,最简单的方法是JSON.stringify
,但是,考虑到数据的范围是众所周知的,这会增加许多不必要的信息。其中一个数组的平均大小约为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建议对数据使用压缩。 Combining this LZW implementation使用基数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
答案 0 :(得分: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作为有效数字)并存储每个桶的计数而不是数字本身。与其他任何方法相比,这可能会给你更好的压缩和效率。
答案 1 :(得分:0)
假设(在你的测试中)压缩花费的时间比减小尺寸所花费的时间多,你的char编码是没有位移的最小值。您当前正在为每个数字使用一个字节,但如果它们保证足够小,则可以在每个字节中放置两个数字。这可能是一个过度优化,除非这是你的代码中非常热门的部分。
答案 2 :(得分:0)
您可能需要考虑使用Uint8Array
或ArrayBuffer
。 This blogpost显示了它是如何完成的。复制他的逻辑,这是一个例子,假设你有一个名为Uint8Array
的现有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
});