C# 如何使用linq获得字典中项目值内变量的不同计数

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 有没有一种方法可以在不复制的情况下获得

我有一个大约有4000万项的字典,我试图根据字典中每个keyvaluepair的值中定义的ulong得到一个不同的计数

我目前的做法是:

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;
    }