筛选.Net中包含(几乎)重复项的列表的最有效方法
我有一个.Net后端,它允许我通过相应的客户端API,通过它们的.Id和.Revision属性来查询项目,更好的是,通过提供这些组合的列表来批量查询项目 但是,每个.Id在每个查询中只能出现一次,但输入中确实包含多次具有相同Id的某些条目,但具有不同的.Revision值,例如:筛选.Net中包含(几乎)重复项的列表的最有效方法,.net,algorithm,linq,sorting,grouping,.net,Algorithm,Linq,Sorting,Grouping,我有一个.Net后端,它允许我通过相应的客户端API,通过它们的.Id和.Revision属性来查询项目,更好的是,通过提供这些组合的列表来批量查询项目 但是,每个.Id在每个查询中只能出现一次,但输入中确实包含多次具有相同Id的某些条目,但具有不同的.Revision值,例如: .Id | .Revision 1 | 1 1 | 2 2 | 1 (unique .Id) 3 | 3 3 | 5 4 | 2 (unique .Id) 5 | 1 (unique .Id
.Id | .Revision
1 | 1
1 | 2
2 | 1 (unique .Id)
3 | 3
3 | 5
4 | 2 (unique .Id)
5 | 1 (unique .Id)
。。因此,Id为1和3的条目基本上会导致问题,我想知道检索所有组合的最有效方式(即查询量最少)是什么
最糟糕的情况是,在运行时一个接一个地检索所有组合,而忽略了潜在的批量/批处理机制,但即使这在逻辑上会返回正确的项集,它显然很慢
如何获得最大的unqiue.Id/.Revision组合集,并以最少的批数将剩余的多个-.Id组合组合在一起。。高效?通过循环中的几个LINQ表达式,您应该能够相对轻松地实现这一点 例如,假设您有一个
Item
类,如下所示:
public class Item
{
public int Id { get; set; }
public int Rev { get; set; }
}
以及这些项目的列表:列表项要批量查询的代码>。在一个批中,Id
不能出现多次
使用Distinct
,您可以非常轻松地获得第一个查询:
var queryItems = Items.Distinct(new ItemIdComparer()).ToList();
还有你的比较器:
public class ItemIdComparer: IEqualityComparer<Item>
{
public int Equals(Item x, Item y)
{
return x.Id == y.Id;
}
public int GetHashCode(Item x)
{
return x.Id;
}
}
如果将其放入循环中,则可以重复执行该操作,直到剩余
列表为空:
var workingItems = Items.ToList();
while (workingItems.Count > 0)
{
var queryItems = workingItems.Distinct(new ItemIdComparer()).ToList();
var leftover = workingItems.Except(queryItems, new ItemComparer()).ToList();
DoQuery(queryItems);
workingItems = leftover;
}
使用此算法,只需两次查询即可获得所有项目的信息。第一个将得到项目1.1、2.1、3.3、4.2和5.1。第二个查询将得到1.2和3.5。给定此格式的条目列表:
public class Entry
{
public int Id { get; set; }
public int Version { get; set; }
}
按Id分组,然后投影一个新的元素列表,每个条目的Id、版本和等级标记为批号,怎么样?排名将在具有相同Id的所有条目中。然后,您可以将具有相同批号的所有条目分组,并一次提交一批
以下是我的表达:
var entries = GenerateEntries();
var result = entries
.GroupBy(e => e.Id)
//project new entries with a batch number
.SelectMany(g => g.Select((e, i) => new { Id = e.Id, Version = e.Version, Batch = i }))
.GroupBy(e => e.Batch);
linq映射到的底层技术是什么?@CapTec没有用于查询后端的linq提供程序,查询之前的对象是纯内存对象,属于自定义类型,基本上客户端API只接受int[]作为.Id和.Revision值。因此,以最少的批处理量在内存中本地进行批处理。您可以从唯一ID生成一个树,并且在每个分支下,每个修订都有节点。这样,您就可以在每个节点需要时查询api。(以说话的方式思考你的问题)。不过我可能误解了你的问题。我对XML也做了类似的工作,以便在运行内存中保持较低的内存占用,相同的主体可以用于查询API。虽然这可以工作,但需要4个单独的查询来获取示例中项目的信息。这可以分两步完成。我不明白这将如何导致对数据库的更多查询。你能解释一下吗?在执行任何查询之前,所有这些逻辑都在他的内存列表中运行。我编写了一个快速应用程序来仔细检查这一点,它导致了两个批次。第一个有1.1、2.1、3.3、4.2和5.1。第二批为1.2和3.5。这和你的代码不一样吗?GetHashCode
应该是x.Id^x.Rev
,而不是x.Id^y.Id
。@Porges:谢谢。固定的。
public class Entry
{
public int Id { get; set; }
public int Version { get; set; }
}
var entries = GenerateEntries();
var result = entries
.GroupBy(e => e.Id)
//project new entries with a batch number
.SelectMany(g => g.Select((e, i) => new { Id = e.Id, Version = e.Version, Batch = i }))
.GroupBy(e => e.Batch);