Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 压缩格式的数据_C#_Algorithm - Fatal编程技术网

C# 压缩格式的数据

C# 压缩格式的数据,c#,algorithm,C#,Algorithm,我需要一个库,它可以帮助我以压缩格式保存和查询数据(本质上是一个迷你DSL),以下是我想要的示例: 更新1-请注意,上述示例中的数字被缩小,以便于遵循逻辑,实际数字受c#long类型容量的限制,例如: 1,18,28,29,39184567891845679018456792184567896 样本原始数据集:1,2,3,8,11,12,13,14 压缩样本数据集: 1..3,8,11..14 最好能将1,2,4,5,6,7,8,9,10呈现为1..10-3 查询样本数据集: 查询1(获取范围)

我需要一个库,它可以帮助我以压缩格式保存和查询数据(本质上是一个迷你DSL),以下是我想要的示例:

更新1-请注意,上述示例中的数字被缩小,以便于遵循逻辑,实际数字受
c#long
类型容量的限制,例如:
1,18,28,29,39184567891845679018456792184567896

样本原始数据集:
1,2,3,8,11,12,13,14

压缩样本数据集:
1..3,8,11..14

最好能将
1,2,4,5,6,7,8,9,10
呈现为
1..10-3

查询样本数据集:

查询1(获取范围):
1..5
->
1..3

查询2(检查该值是否存在)
?2
->
正确

查询3(获取多个范围和标量值):
1..5,11..12,14
->
1..3,11..12,14


我不想从头开始开发它,我更愿意使用已经存在的东西。

我不知道有任何现成的库可以完全满足您的需要,但我不确定您是否需要

我建议您考虑使用现有的< BitArray > <代码>类。如您的示例所示,如果您对压缩小整数集感兴趣,那么具有256位的单个
位数组可以表示
[0..255]
范围内的任何整数集。当然,如果您的典型集合中只有5个整数,那么这种方法实际上会扩展您的存储需求;您必须根据自己对集合的了解来确定此类数组的正确大小

我建议您也将数据视为整数集,因此您的示例
1,2,3,8,11,12,13,14
将通过设置
位数组中的相应位来表示。然后,查询操作减少到测试
位数组
和数据
位数组
之间的交集

顺便说一句,我认为你的例子2,它转换了
2->true
,最好留在将整数集映射到整数集的函数域中,即它应该转换
2->2
。如果需要,请编写另一个返回布尔值的方法


我想您需要编写代码将整数打包成
位数组
并将
位数组
解包成整数,但这是压缩成本的一部分。

以下是我读了您的问题几天来的一些想法。我不能确定它们是否真的适用于您的用例,但我希望您能在这里找到有用的东西

存储压缩的数据 减少数字占用磁盘空间的步骤:

  • 如果您的值介于1和~10M之间,请不要使用
    long
    ,请使用
    uint
    。(每个数字4个字节。)
  • 实际上,不要使用
    uint
    。将数字存储为7位到一个字节,剩余的位用于表示“此数字中有更多字节”。(那么1-127将放入1字节,128-~16k放入2字节,16k-~2M放入3字节,2M-~270M放入4字节。)
这将使您的存储从每个数字8个字节(如果您最初将它们存储为
long
s)减少到平均3个字节。此外,如果您最终需要更大的数字,则可变字节存储器将能够容纳它们

然后,我可以想出一些方法来进一步减少它,因为你知道数字总是在增加,可能包含大量的运行。哪种方法最适合您,只有您可以通过在实际数据上尝试才能知道

  • 对于每个实际数字,存储两个数字:数字本身,然后是其后面相邻的数字(例如
    2,3,4,5,6
    =>
    2,4
    )。您必须单独存储一个数字,例如
    8,0
    ,这样会增加这些数字的存储空间,但如果您的数据有很多次运行(特别是长时间运行),这将平均减少存储空间。您可以在运行中进一步存储“单个间隙”,例如
    1,2,3,5,6,7
    =>
    1,6,4
    (明确地说,
    4
    太小,无法作为下一次运行的开始),但这将使处理更加复杂,不会节省太多空间,因此我不会费心
  • 或者,不存储数字本身,而是存储增量(因此
    3,4,5,7,8,9
    =>
    3,1,1,2,1,1
    。这将减少用于存储较大数字的字节数(例如
    1500015005
    (4字节)=>
    15000,5
    (3字节))。此外,如果数据包含大量运行(例如大量
    1
    字节),然后它会很好地压缩(例如zip)
代码处理 我只是建议您编写两个方法,将文件从磁盘流式传输到
IEnumerable
(或者
ulong
,如果您的数字更大),然后执行相反的操作,同时处理上面实现的任何内容

如果您以惰性方式执行此操作—使用
yield return
在从磁盘读取并计算数字时返回数字,并将数字流式传输到磁盘,而不是将其保存在内存中并立即返回,则无论存储数据的大小如何,您都可以降低内存使用率

(我认为,但我不确定,即使是压缩流和其他压缩流也能让您在不将数据全部存储在内存中的情况下对数据进行流式处理。)

质疑 如果您正在比较两个大数据集,我不建议使用LINQ的
Intersect
方法,因为它需要将一个源完全读入内存。但是,正如您所知,两个序列都在增加,您可以编写一个类似的方法,只需为每个序列保留一个枚举器

如果您正在根据用户输入的一个小数字列表查询一个数据集,您可以愉快地使用LINQ的
Intersect
方法,就像它当前一样