Linq检索在集合和不在集合中的项之间发生更改的项
本文关键字:集合 之间 检索 Linq | 更新日期: 2023-09-27 18:10:47
以下是我的分类:
public class XDetail
{
public string Name { get; set; }
public int ID { get; set; }
}
public class X
{
public int XID { get; set; }
public int ID { get; set; }
}
它们之间共享ID以链接X和XDetail(一对多关系),X和XDetail实际上是类型化的datarow。我使用以下linq查询读取一个文件,并形成一个匿名类型:
var results = (from line in File.ReadAllLines(file)
select new
{
XID = int.Parse(line.Substring(0, 8).TrimStart('0')),
Name = line.Substring(8, 255).Trim()
}).ToList();
此数据用于对照现有的X/XDetail进行检查,以进行适当的更改或添加新记录。我将结果包装在检查中,以查看当序列没有结果时是否会抛出. tolist()。XList是一个List, XDetailList也是一个List。
从那里,我尝试一个奇特的linq查询来匹配适当的项:
var changedData = from x in XList
join xDetail in XDetailList on x.ID equals xDetail.ID
where
(!results.Any(p => p.XID.Equals(x.XID))
|| !results.Any(p => p.Name.Equals(xDetail.Name)))
select new
{
XValue = x,
XDetailValue = xDetail,
Result = (from result in results
where result.Name.Equals(xDetail.Name)
select result).SingleOrDefault()
};
我的新问题是,这个查询只会向我提供X/XDetail中发生了什么变化,而不是什么新的。为了完成获得新的内容,我必须在测试小数据集(X/XDetail的3个现有条目)时运行另一个看起来足够好的查询,但是当我尝试真正的文件并通过它的~7700个条目进行切换时,我似乎有无穷无尽的处理。
对于已经包含在X/XDetail中的以下示例数据集:
XID: 1, Name: Bob, ID: 10
XID: 2, Name: Joe, ID: 20
XID: 3, Name: Sam, ID: 30
的结果文件包含:
XID: 2, Name: Bob2
id: 3, Name: NotSam
id: 4, Name: NewGuy
id: 5,名称:NewGuy2
我想能够得到一个结果集包含:
{XID: 2, Name: Bob2}, x, xDetail
{XID: 3, Name: NotSam}, x, xDetail
{XID: 4, Name: NewGuy}, x, xDetail
{XID: 5, Name: NewGuy2}, x, xDetail
我希望x和xDetail作为结果集的一部分,这样我就可以使用这些类型化的数据行来进行必要的更改。
我试着问了这样一个问题:
var newData = from result in results
join x in XList on result.XID equals x.XID
join xDetail in XDetailList on x.ID equals xDetail.ID
where
(x.XID == result.XID && xDetail.Name != result.Name)
select new
{
XValue = x,
XDetailValue = xDetail,
Result = result
};
由于连接指示我只会在数据中获取更改项,因此我真的希望能够添加不在X/XDetail中的数据,并停止过去2.5小时一直在处理我的~7700更改文件的系统。我觉得我已经盯着这个和相关的查询太久了,无法发现我应该做些什么来正确地为它塑造一个where子句。
是否有一种方法来构建linq查询来查找更改的数据和X/XDetail中不存在的数据,并将其返回到一个新的结果集中进行处理?
我认为你的性能问题与你的查询的复杂性有关,这可能是围绕O(n^2)
。
因此,首先我建议您在查找结构中设置当前数据,像这样(*):
var joinedByXID = (from x in XList
join xDetail in XDetailList on x.ID equals xDetail.ID
select new { X = x, XDetail = xDetail })
.ToLookup(x => x.X.ID);
现在,我不确定,但我假设通过说"更改的数据"你的意思是条目的列表已经存在的XID,但一个新的名称,是对的吗?
如果是这样,您可以使用以下查询获得"更改的数据":
var changedData = results
.Where(r => joinedByXID.Contains(r.XID))
.SelectMany(r => joinedByXID[r.XID]
.Where(x => x.XDetail.Name != r.Name)
.Select(old => new {XValue=old.X, XDetailValue=old.XDetail, Result=r}));
然后,如果"新数据"指的是具有新XID的条目列表(XID目前不在XList/xdetailist中),那么您无法将它们与X/Xdetail元素匹配,因为没有任何X/Xdetail元素,所以简单地:
var newData = results
.Where(r => !joinedByXID.Contains(r.XID));
(*)
实际上,为了更快,您可以将数据安排在字典的字典中,其中外键是XID,内键是Name。