我正在从具有相同ID的两个来源中提取数据。一组数据具有元数据,而另一组则没有。最后,我要列出一个具有共同信息的列表。
public class Record
{
public string Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string MetaInfo1 { get; set; }
public string MetaInfo2 { get; set; }
}
List<Record> doc = new List<Record>(); //About 100k items, MetaInfo is null
List<Record> docWithMeta = new List<Record>(); //About 50k items, Name and Title Null
我尝试使用Join
,但是第二个数据集并不总是具有匹配的ID,最终结果是一个List,仅包含具有匹配项的项目。最终结果应该具有缺少元数据的记录,这是可以的。
var joint = doc.Join(docWithMeta,
a => a.Id,
b => b.Id,
(a, b) => new Record
{
Id = a.Id,
Name = a.Name,
Title = a.Title,
MetaInfo1 = b.MetaInfo1,
MetaInfo2 = b.MetaInfo2,
}).ToList();
我尝试使用嵌套的foreach
循环来查找匹配项并将属性添加到新列表中,该列表可以正常工作,但是代码非常慢。
List<Record> newDoc = new List<Record>();
foreach (Record rec in doc)
{
foreach (Record recMeta in docWithMeta)
{
if (rec.Id == recMeta.Id)
{
rec.MetaInfo1 = recMeta.MetaInfo1;
rec.MetaInfo1 = recMeta.MetaInfo1;
}
}
newDoc.Add(rec);
}
我也尝试过使用GroupJoin
,但是我不确定如何使用它,并且不断收到null异常。
var results = doc.GroupJoin(docWithMeta,
a => a.Id,
b => b.Id,
(a, result) => new Record
{
Id = a.Id,
MetaInfo1 = result.FirstOrDefault().MetaInfo1 //null exception here
}).ToList();
更新
使用下面的一些建议,我得到了一种性能足够好的方法。
var results = doc.GroupJoin(docWithMeta,
a => a.Id,
b => b.Id,
(a, result) => new
{
Foo = f,
Bar = result }
}).SelectMany(
x => x.Bar.DefaultIfEmpty(),
(x, y) => new Record
{
Id = x.Foo.Id,
Name = x.Foo.Name,
MetaInfo1 = y == null ? null : y.MetaInfo1,
MetaInfo2 = y == null ? null : y.MetaInfo2
}).ToList();
每当包含元数据的数据集没有与第一个数据集匹配的ID时,我都会一直获取NullReferenceException。我只是使用三元运算符来检查null
。必须有更好的方法。
答案 0 :(得分:1)
我现在无法检查此代码,但我认为它一定可以工作
doc.GroupJoin(
docWithMeta,
a => a.Id,
b => b.Id,
(a, b) => new { doc = a, meta = b })
.SelectMany(
ab => ab.docWithMeta.DefaultIfEmpty(),
(x, y) => new { doc = x.doc, meta = y })
.Select(s => new
{
Id = s.doc.Id,
Name = s.doc.Name,
Title = s.doc.Title,
MetaInfo1 = s.meta?.MetaInfo1 == null ? "" : s.meta?.MetaInfo1,
MetaInfo2 = s.meta?.MetaInfo2 == null ? "" : s.meta?.MetaInfo2,
}).ToList();