C# 如何使用linq获得字典中项目值内变量的不同计数
我有一个大约有4000万项的字典,我试图根据字典中每个keyvaluepair的值中定义的ulong得到一个不同的计数 我目前的做法是:C# 如何使用linq获得字典中项目值内变量的不同计数,c#,linq,C#,Linq,我有一个大约有4000万项的字典,我试图根据字典中每个keyvaluepair的值中定义的ulong得到一个不同的计数 我目前的做法是: int Total = (from c in Items select c.Value.Requester).Distinct().Count(); 唯一的问题是,我的应用程序使用了大约3.9GB的ram,而这种方法似乎是复制它找到的项目(恰好是字典中项目的95%),所以在GC着手处理之前,ram的使用量又增加了几GB 有没有一种方法可以在不复制的情况下获得
int Total = (from c in Items select c.Value.Requester).Distinct().Count();
唯一的问题是,我的应用程序使用了大约3.9GB的ram,而这种方法似乎是复制它找到的项目(恰好是字典中项目的95%),所以在GC着手处理之前,ram的使用量又增加了几GB
有没有一种方法可以在不复制的情况下获得不同的计数?不,你不能这样做。它需要复制这些值,因为它需要记住以前看到的值 如果您有一个列表,其中项目按Value.Requester排序,那么您可以通过一次线性扫描来计算不同的值,而无需复制。但你没有 如果您知道您的值在特定范围内(例如1到100000000),您可以使用位数组编写一个内存效率更高的算法。您可以创建一个100000000位的数组(320万整数的数组),该数组只消耗大约12.5兆字节,并使用它存储您看到的值 以下是一些您可以使用的代码:
// Warning: this scans the input multiple times!
// Rewriting the code to only use a single scan is left as an exercise
// for the reader.
public static int DistinctCount(this IEnumerable<int> values)
{
int min = values.Min();
int max = values.Max();
uint[] bitarray = new uint[(max - min + 31) / 32];
foreach (int value in values)
{
int i = (value - min) / 32;
int j = (value - min) % 32;
bitarray[i] |= (uint)(1 << j);
}
uint count = 0;
for (int i = 0; i < bitarray.Length; ++i)
{
uint bits = bitarray[i];
while (bits != 0)
{
count += bits & 1;
bits >>= 1;
}
}
return (int)count;
}
你可能需要重新考虑如何创建字典。如果您是从一个文件构建它,那么您可能希望一次读取它的较小部分。要获得不同的项,可以从字典文件的每个块开始向
哈希集添加项。散列集的最终大小将是不同项目的数量。这种方法可能仍然很慢,因为每次向集合添加值时,集合都需要进行工作以确保值不存在
我想从Mark的回答中得到一些提示:在将输入读入应用程序之前,确保输入已排序:如果数据已排序,则可以在一次传递中计算不同的项(您基本上计算n
处的值与n+1处的值不同的次数,因为其他人已经指出,如果不复制,您使用的结构将无法实现您想要的功能
如果您真的需要对当前结构执行此操作,我认为您必须引入一些冗余…即,当您插入/删除此“大字典”中的项目时,请维护第二个较小的字典,该字典只保留带有计数的不同值(注意多线程问题)
另一种选择是:
使用数据库…如果需要的话,可以使用内存中的数据库…但是我非常确定基于磁盘的数据库可以胜任这项任务(每小时4000万个数据库不到每秒20K)…我更喜欢Oracle…但是SQLite、Postgres等在这方面也非常好…您可以将SQLite用作纯粹的“内存中的数据库”如果您想要和/或您可以创建一个RAM磁盘,并将DB文件放在那里。虽然在大多数情况下它实际上是无用的,但从技术上讲,通过一个简单的O(n^2)算法就可以做到这一点(这将需要几分钟的时间来对400000项执行)
public static int DistinctCount(此IEnumerable值)
{
int max=values.max();
int last=int.MinValue;
int结果=0;
做
{
int current=int.MaxValue;
foreach(值中的int值)
{
如果(值last)
{
电流=值;
}
}
结果++;
last=当前值;
}while(last!=max);
返回结果;
}
遍历你的字典。但是为什么你要用字典来存储这么多项目呢?我想你需要从不同的角度来研究这个问题,而不是使用调整/不同的数据structure@ojlovecd我确信一个基于硬盘的数据库每秒可以支持10-20k的插入。这里的值是多少?它是一个大的stru吗有可能是ct吗?如果只是引用的副本,保存“副本”通常不是问题……好吧,它不是从文件中读取的。它从零项开始,这本词典只记录它在过去一小时内看到的数据包(平均每小时4000万个)我只是不确定一个基于硬盘的数据库是否能跟上每秒如此多的插入。
int Total = (from c in Items select c.Value.Requester).DistinctCount();
public static int DistinctCount(this IEnumerable<int> values)
{
int max = values.Max();
int last = int.MinValue;
int result = 0;
do
{
int current = int.MaxValue;
foreach (int value in values)
{
if (value < current && value > last)
{
current = value;
}
}
result++;
last = current;
} while (last != max);
return result;
}