C# 使用由0和1组成的数据实现最佳压缩?
我正试图为矩阵中仅包含1和0的数据实现尽可能最好的压缩 为了证明我的意思,这里有一个6×6矩阵示例:C# 使用由0和1组成的数据实现最佳压缩?,c#,compression,C#,Compression,我正试图为矩阵中仅包含1和0的数据实现尽可能最好的压缩 为了证明我的意思,这里有一个6×6矩阵示例: 1,0,0,1,1,1 0,1,0,1,1,1 1,0,0,1,0,0 0,1,1,0,1,1 1,0,0,0,0,1 0,1,0,1,0,1 我想把它压缩成尽可能小的字符串或字节数组。我需要压缩的矩阵更大(总是4096乘40961s和0s) 我想它可能会被压缩得很重,但我不知道怎么压缩。我将标记最佳压缩作为答案。性能并不重要。尝试创建自己的算法来专门压缩这些数据很可能不会产生太多效果 Cre
1,0,0,1,1,1
0,1,0,1,1,1
1,0,0,1,0,0
0,1,1,0,1,1
1,0,0,0,0,1
0,1,0,1,0,1
我想把它压缩成尽可能小的字符串或字节数组。我需要压缩的矩阵更大(总是4096乘40961s和0s)
我想它可能会被压缩得很重,但我不知道怎么压缩。我将标记最佳压缩作为答案。性能并不重要。尝试创建自己的算法来专门压缩这些数据很可能不会产生太多效果
Create a GZipStream with Max CompressionLevel
Run a 4096x4096 loop
- set all 64 bits of a ulong to bits of the array
- when 64 bits are done write the ulong to the compressionstream and start at the first bit again
这将非常容易地将多维数据集添加到一个相当压缩的内存块中嗯。。。在不了解问题域的情况下,尽可能小是不可能的 以下是一般方法:
0 => 111
1 => 10
, => 0
\r => 1100
\n => 1101
示例矩阵的收益率(以位为单位):
如果可以排除逗号、换行符和回车符,则只需要一个字符来存储每个值。虽然现在你需要知道解码时矩阵的维数。如果不这样做,则可以将其存储为int,如果计划序列化数据,则可以将其存储为数据本身
比如:
var input = @"1,0,0,1,1,1
0,1,0,1,1,1
1,0,0,1,0,0
0,1,1,0,1,1
1,0,0,0,0,1
0,1,0,1,0,1";
var values = new List<bool>();
foreach(var c in input)
{
if (c == '0')
values.Add(false);
else if (c == '1')
values.Add(true);
}
var ba = new BitArray(values.ToArray());
var输入=@“1,0,0,1,1,1
0,1,0,1,1,1
1,0,0,1,0,0
0,1,1,0,1,1
1,0,0,0,0,1
0,1,0,1,0,1";
var值=新列表();
foreach(输入中的var c)
{
如果(c=='0')
值。添加(false);
else如果(c=='1')
值。添加(true);
}
var ba=新的位数组(values.ToArray());
然后序列化位数组。您可能需要添加一些填充位来正确解码数据。(4096*4096可被8整除)
除非矩阵中有大量重复模式(是的,我假设数据大部分是随机的),否则BitArray方法应该可以获得最大的压缩。我假设您希望将字符串压缩为其他字符串,即使您的数据实际上是二进制的。我不知道最好的压缩算法是什么(这取决于您的数据),但您可以将输入文本转换为位,压缩这些位,然后再次使用base-64编码将压缩的字节转换为字符串。这将允许您从一个字符串切换到另一个字符串,并且仍然应用您选择的压缩算法 NET framework提供了一个类,允许您压缩字节流。第一步是创建一个自定义的
流
,允许您读写文本格式。由于没有更好的名字,我把它命名为TextStream
。请注意,为了简化一些问题,我使用\n
作为行结尾(而不是\r\n
)
为了测试它,我使用了一种方法创建了一个随机字符串(使用固定种子始终创建相同的字符串):
String CreateRandomString(Int32宽度,Int32高度){
var random=新随机数(0);
var stringBuilder=新的stringBuilder();
对于(变量i=0;i0&&j==0)
stringBuilder.Append('\n');
否则,如果(j>0)
追加(',');
stringBuilder.Append(random.Next(2)=0?'0':'1');
}
}
返回stringBuilder.ToString();
}
创建随机4096 x 4096字符串的未压缩大小为33554431个字符。这是压缩到2797056个字符,这是一个减少到约8%的原始大小
跳过base-64编码将进一步提高压缩比,但输出将是二进制而不是字符串。如果你还把输入看作二进制,实际上你得到的结果等于0和1的随机数据:
Input bytes: 4,096 x 4,096 / 8 = 2,097,152
Output bytes: 2,097,792
Size after compression: 100%
输入字节:4096 x 4096/8=2097152
输出字节:2097792
压缩后尺寸:100%
简单地转换成字节要比通过一个deflate来转换好。但是,使用随机输入,但使用25%0和75%1,您会得到以下结果:
Input bytes: 4,096 x 4,096 / 8 = 2,097,152
Output bytes: 1,757,846
Size after compression: 84%
输入字节:4096 x 4096/8=2097152
输出字节:1757846
压缩后尺寸:84%
多少deflate将压缩您的数据实际上取决于数据的性质。如果是完全随机的,在将文本转换为字节后,您将无法获得太多的压缩。先将它们压缩为位,然后对生成的位应用任何好的压缩算法如何?然后必须压缩2MB的随机字节。可能适合你。最终结果必须是字符串吗<代码>字节[]更有意义。字节是
String Compress(String text) {
using (var inputStream = new TextStream(text))
using (var outputStream = new MemoryStream()) {
using (var compressedStream = new DeflateStream(outputStream, CompressionMode.Compress))
inputStream.CopyTo(compressedStream);
return Convert.ToBase64String(outputStream.ToArray());
}
}
String Decompress(String compressedText, Int32 bitsPerLine) {
var bytes = Convert.FromBase64String(compressedText);
using (var inputStream = new MemoryStream(bytes))
using (var outputStream = new TextStream(bitsPerLine)) {
using (var compressedStream = new DeflateStream(inputStream, CompressionMode.Decompress))
compressedStream.CopyTo(outputStream);
return outputStream.ToString();
}
}
String CreateRandomString(Int32 width, Int32 height) {
var random = new Random(0);
var stringBuilder = new StringBuilder();
for (var i = 0; i < width; ++i) {
for (var j = 0; j < height; ++j) {
if (i > 0 && j == 0)
stringBuilder.Append('\n');
else if (j > 0)
stringBuilder.Append(',');
stringBuilder.Append(random.Next(2) == 0 ? '0' : '1');
}
}
return stringBuilder.ToString();
}
Input bytes: 4,096 x 4,096 / 8 = 2,097,152
Output bytes: 2,097,792
Size after compression: 100%
Input bytes: 4,096 x 4,096 / 8 = 2,097,152
Output bytes: 1,757,846
Size after compression: 84%