我正在用C#处理大文件(希望如此),我需要一种方法来确定每列文件中不同值的数量。我已经阅读了所有与C#确定不同值有关的问题。挑战在于,由于某些文件的大小以及列中可能有数千万个不同的值(可能有数百列 - 各种数据类型),因此需要创建列表,字典或数组等。每一列 - 然后使用之前回答的问题中描述的技术 - 将使我面临达到2 GB内存限制的危险。
目前,我正在一行读取/处理文件,每行“清理和清理”数据,更新聚合结果,然后将每个处理过的行写入输出文件,然后将其批量插入SQL。迄今为止的表现实际上相当不错。
由于数据最终落在MS SQL中,作为后备,我可以使用SQL来确定不同的值,但我希望能够在登陆SQL之前执行此操作。任何想法或建议都表示赞赏。
更新:对于每个字段,我创建了一个哈希表,并为每个字段添加了新的不同值。在处理结束时,我使用 myDistinctValues.Count 获得计数。这适用于小文件,但正如我所担心的,我得到一个大文件
System.OutOfMemoryException
抛出。根据建议,我确实尝试添加
<runtime>
<gcAllowVeryLargeObjects enabled="true"/>
</runtime>
到我的应用程序配置,但没有帮助。
答案 0 :(得分:1)
虽然我的解决方案并不优雅,但肯定有更好的解决方案(BTree?),我找到了一些有用的东西,并且认为我会分享它。我不能成为唯一一个想要确定非常大的文件中字段的不同计数的人。也就是说,我不知道这将如何扩展到数以亿计或数十亿的记录。在某些时候,如果有足够的数据,就会达到单个阵列的2GB大小限制。
什么没有用?
做了什么工作:
通过这种方式,我可以获得每个字段的不同值的计数,而不必同时为每个字段填充和维护内存中的哈希表,这会导致内存不足错误。
答案 1 :(得分:0)
您期望有多少不同的值?我使用了以下简单的应用程序:
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
Dictionary<string, int> ds = new Dictionary<string, int>;
Random r = new Random();
for (int i = 0; i < 100000000; i++) {
string s = Guid.NewGuid().ToString();
d[s] = r.Next(0, 1000000);
if (i % 100000 == 0)
{
Console.Out.WriteLine("Dict size: " + d.Count);
}
}
}
}
与.net 4.6.1,x64构建目标在我的机器内存不足之前,我已经获得了4000万个独特的对象和5.5千兆字节的内存消耗(此时正忙于其他事情,对不起)..
如果你要使用数组,你可能需要一个看起来像这样的app.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup>
<runtime>
<gcAllowVeryLargeObjects enabled="true"/>
</runtime>
</configuration>
您应该能够计算出跟踪不同值及其计数所需的记忆。如果您认为它将在数亿美元中,我建议您一次只能处理一列。
只是一个小小的澄清:当我读到“不同值的数量”时,它让我觉得你想要跟踪每个值出现的次数。这就是我使用Dictionary<string, int>
的原因 - 字符串是计算的不同值,int是计数
如果您希望将X百万/十亿的值列表重新排序到不同的值,而不需要计算出现次数,那么HashSet可能会减轻重量
答案 2 :(得分:0)
您是否考虑获取值的哈希码(假设它不能大于128个字节),创建哈希集并执行以下操作:
static void Main(string[] args)
{
List<object> vals = new List<object> {1, 'c', "as", 2, 1};
foreach(var v in vals)
Console.WriteLine($"Is uniques: {IsUniq(v)}");
Console.ReadKey();
}
private static HashSet<object> _hashes = new HashSet<object>();
private static bool IsUniq(object v)
{
return _hashes.Add(v);
}
对于100万个元素,它应该是100-150兆字节的原始数据。
答案 3 :(得分:0)
您是否尝试将文件加载到数据表中,然后通过数据视图(不创建副本)进行不同的选择? 看看
这是一些伪代码
Read from File into Datatable
Create DataView with sort on the column you want
UniqueCount = 0
var CurrentValue="<some impossible value>"
For each ViewRow in DataView
If CurrentValue <> ViewRow["MyColumn"]
UniqueCount ++
UniqueCount should give me my result
这将是有效的,因为您只使用2个变量UniqueCount和CurrentValue来循环数据。 您还在数据视图中进行排序,在处理时不会复制数据。
希望这有帮助