c#中许多键值相同时减少数据内存



我有很多数据在以下文本形式:

4c5c,6c4h,486,30
4c5c,6c5h,486,30
4c5c,6c6h,458,0
4c5c,6c7h,648,9
4c5c,6c8h,648,9
3sTs,QsKs,182,0
3sTs,QsAs,182,0
3sTs,KsAs,743,0
3sJs,4s5s,495,0
3sJs,4s6s,625,0
3sJs,4s7s,739,0
3sJs,4s8s,739,0
3sJs,4s9s,739,0
3sJs,4sTs,739,0
3sJs,4sQs,182,0
3sJs,4sKs,739,0
3sJs,4sAs,625,0
3sJs,5s6s,625,0
3sJs,5s7s,739,0
3sJs,5s8s,739,0

在每一行中,前两项表示一个键,后两项表示值。如。关键:3 sj 5 s8值:739,0

我有超过140亿行这样的行,并将它们存储在字典中以便快速访问。这是有问题的,因为有大约250GB的文本数据,这需要大量的内存,当存储在字典。然而,我注意到许多值对于多个键是相同的。是否有一些字典的替代方法,我可以在减少内存需求的情况下存储这些数据,以利用许多值重复的事实?我以前没有使用过c#程序的数据库,但做了一点postgres - sqlite是我最好的/唯一明智的选择,它会减少我的应用程序大小到一个可管理的大小分发?

我不确定你的价值是什么。你能把你的价值观编码得多小?我假设您可以将它们打包成4个字节。

所以你的键是一个描述4张扑克牌的文本字符串。所以可能的键空间不超过52^4 ~= 7.3e6。在所有可能的键中,有值的比例是多少?它离它们都近吗?

与其使用文本字符串来表示密钥,不如为每张卡片分配一个数字(0-51)。然后构建Int32=k1 + k2*52 + k3*(52^2) + k4*(52^3)

如果要为大多数键存储值,则不需要字典。你可以使用一个长度为52^4的数组。这样就不需要为键本身分配任何内存。只需要4bytes * 52^4 ~= 28MB的内存

然后将这个数组存储在磁盘上,我将它保存在zip归档文件中。如果你有很多相似的值,应该压缩得很好。

您可能希望将该数据划分为多个部分,这样您就不必将整个结构解压缩到内存中。但是,这取决于您希望在运行时如何使用这些数据。

在您的评论中提到的约束下,您可以将显示的示例数据放在一个5维数组中。你要的是样品,这就是。我将从示例数据中取出第一行:

4 c5c 6 c4h, 486, 30

首先,您必须为卡片分配数值。这取决于你如何在0到51之间给它们编号。为简单起见,我将使用

4c = 0
5c = 1
6c = 2
4h = 3

数组应该像这样:

var data = new short [52, 52, 52, 52, 2];

前四个维度表示密钥(从0到51的卡号),第五个维度表示值的索引(0或1)。然后,您可以像这样访问数组(这里我将从示例数据的第一行设置值):

data[0, 1, 2, 3, 0] = 486;
data[0, 1, 2, 3, 1] = 30;

如果存在无效或不需要的卡片组合,则不将其放入数组中(所有元素默认初始化为0)。该数组的固定大小为29,246,464字节。通过卡号访问数组元素是最快的方法。但正如我在评论中所写的,这只适用于您所呈现的数据结构。不清楚其他三张卡是如何关联的,这个数组只能构建您提供的数据样本。还是希望能帮上忙。

最新更新