我有这个类暴露IEnumerable<Record>
如下(实现细节遗漏):
public class SomeFileReader() {
public IEnumerable<Record> Records()
{
using (StreamReader sr = new StreamReader(this.Path, this.Encoding, true))
{
var hdr = this.HeaderParser.Parse(sr.ReadLine()); //Parse, but further ignore header (the HeaderParser might throw though)
while (!sr.EndOfStream)
yield return this.RecordParser.Parse(sr.ReadLine()) as Record;
}
}
Record
具有许多其他属性(因此具有相当大的“内存/存储明智”),Id
属性(由{2}组成的Key
对象“部分”)。为了完整性,这看起来像:
public class Key : IEquatable<Key>
{
public string OperatorCode { get; set; }
public string Key { get; set; }
public bool Equals(Key other)
{
return (this.OperatorCode.Equals(other.OperatorCode, StringComparison.OrdinalIgnoreCase))
&& (this.Key.Equals(other.Key, StringComparison.OrdinalIgnoreCase));
}
}
该文件包含“密钥顺序”中的记录,因此它(保证)按记录的ID
磁盘排序。
在内存中,我还要从HashSet<Key>
处理SomeFileReader
条记录。目前我的测试文件只有几兆字节,但我预计这会在不久的将来变得非常大。此时我只是使用Dictionary<Key, Record>
将整个文件读入内存,以便从我的“待处理”记录“列表”中轻松/快速地检索我想要处理的特定记录。这类似于:
var recordsfromfile = MyFileImporter.Records().ToDictionary(k => k.Key.Key);
一旦文件增长(太大),这将是有问题的。
但是因为我正在考虑IEnumerable<Record>
我正在考虑...我不应该将文件完全读入内存 ,因为记录按键顺序排列。一个简单的Intersect()与我的“待处理密钥列表”就足够了。 Key
已经实现了IEquatable
而应该我需要一个根本不难实现的IEQualityComparer<Key>
。但我(想想我)离题..
Intersect()
文档告诉我:
枚举此方法返回的对象时,相交 枚举
first
,收集该序列的所有不同元素。 然后它枚举second
,标记两者中出现的那些元素 序列。 最后,标记的元素按顺序生成 他们被收集了。
(强调我的)
因此,如果我理解正确,如果 first
将是我的IEnumerable<Record>
,该文件仍将完全读入内存。即使它是 second
所有与我的'待处理'“列表”的匹配仍然会被读入内存,这仍然可能是非常大量的数据。或者我误读了文档,这是“最后”绊倒我和/或我是否误解了文档?
显然,我想要阻止的是
长话短说; Intersect()
会做我想做的事吗?我应该使用其他方法吗?嵌套for循环?关于如何有效处理这个问题的任何其他想法?
编辑:已更新,以明确“要处理的密钥列表”实际上是HashSet<Key>
。
P.S。我只是被一个关于在床上使用Linq用于此目的的脑波所击中,在我弄清楚之前无法入睡。不幸的是,我正在度假,距离一个体面的Visual Studio实例只有几英里,只是简单地测试一下。这将不得不等到我的假期之后(所以失误说......我们会看到......)
答案 0 :(得分:2)
var records = new SomeFileReader().Records()
.Where(record => keys.Contains(record.Key));
foreach (var record in records)
{
Process(record);
}
我担心Intersect
文档错了。它实际上首先枚举second
,收集其中的所有内容...然后流first
,产生任何相交的值。
请参阅我的Edulinq blog post on Intersect
,了解其实际功能的详细信息。
在TL; DR意义上,它是:
HashSet<T>
second
first
在我们去的时候从集合中删除项目的事实会阻止相同的元素被放置两次(即使它在first
和second
中出现多次,因为它是一个设定)。
基本上,只要你颠倒了操作数的顺序,我认为你会没事的,所以你这样做:
var result = streamingRecordsFromFile.Intersect(smallCollectionInMemory);