C# 查找与所有其他项目相关的项目
我有以下课程:C# 查找与所有其他项目相关的项目,c#,linq,C#,Linq,我有以下课程: public class Relation { public Int32 SourceId { get; set; } public Int32 TargetId { get; set; } } 以及下列名单: List<Relation> relations = service.GetRelations(); 在这种情况下,TargetId可以是1或2 与所有targetID(1,2)相关的唯一SourceId是sourceID1 SourceId 2仅
public class Relation {
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
以及下列名单:
List<Relation> relations = service.GetRelations();
在这种情况下,TargetId
可以是1或2
与所有targetID(1,2)
相关的唯一SourceId
是sourceID1
SourceId 2
仅与TargetId 1
相关,SourceId 3
仅与TargetId 2
相关
我如何才能做到这一点?以下代码满足您的要求。它有一种单元测试的形式,因此您可以检查不同的场景
[Fact]
public void FindSourcesThatTargetAll()
{
var list = new List<Relation>
{
new Relation(1, 1), new Relation(1, 2), new Relation(2, 1), new Relation(3, 2)
};
var allTargets = list.Select(x => x.TargetId).Distinct().OrderBy(x=>x).ToList();
var dict = list.GroupBy(x => x.SourceId).ToDictionary(x => x.Key,
grouping => grouping.Select(y => y.TargetId).Distinct().OrderBy(x=>x).ToList());
var sourcesThatTargetAll = dict.Where(x => x.Value.Count == allTargets.Count).Select(x => x.Key).ToList();
Assert.Single(sourcesThatTargetAll);
Assert.Equal(1, sourcesThatTargetAll.First());
}
[事实]
public void FindSourcesThatTargetAll()
{
变量列表=新列表
{
新关系(1,1),新关系(1,2),新关系(2,1),新关系(3,2)
};
var allTargets=list.Select(x=>x.TargetId).Distinct().OrderBy(x=>x.ToList();
var dict=list.GroupBy(x=>x.SourceId).ToDictionary(x=>x.Key,
grouping=>grouping.Select(y=>y.TargetId).Distinct().OrderBy(x=>x.ToList());
var sourcesThatTargetAll=dict.Where(x=>x.Value.Count==allTargets.Count);
Assert.Single(sourcesThatTargetAll);
等于(1,sourcesThatTargetAll.First());
}
基本上,我做到了:
dict
variable)您需要收集所有可能的目标ID:
var input = new []
{
new Relation(1, 1),
new Relation(1, 2),
new Relation(2, 1),
new Relation(3, 2),
};
var allTargetId = input.Select(x => x.TargetId).Distinct().ToArray();
然后按源id分组,并在每组中检查allTargetId
中显示的所有组成员:
(1, 1), (1, 2), (2, 1), (3, 2)
var result = input.GroupBy(x => x.SourceId, x => x.TargetId)
.Where(g => allTargetId.All(x => g.Contains(x)))
.Select(g => g.Key)
.ToArray();
注意:为了使这段代码正常工作,我在关系
类中添加了一个构造函数
public class Relation
{
public Relation(int sourceId, int targetId)
{
SourceId = sourceId;
TargetId = targetId;
}
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
编辑 要获取
关系
,可以使用以下查询:
var result = input.GroupBy(x => x.SourceId)
.Where(g => allTargetId.All(x => g.Select(y => y.TargetId).Contains(x)))
.SelectMany(g => g)
.ToArray();
请注意,我只使用LINQ2对象对其进行了测试,因此我不确定如何将其转换为SQL实现这一点的简单方法是按
TargetId
对记录进行分组,然后找到所有SourceId
的交集
var groups = relations.GroupBy(r => r.TargetId).ToArray();
if (groups.Length > 0) {
var set = new HashSet<int>(groups[0]);
for (int i = 1; i < groups.Length; ++i)
set.IntersectWith(groups[i].Select(r => r.SourceId));
}
var groups=relations.GroupBy(r=>r.TargetId.ToArray();
如果(groups.Length>0){
var set=新的HashSet(组[0]);
对于(int i=1;ir.SourceId));
}
在此集合的末尾
将包含与所有TargetId
s公共类关系相关的所有SourceId
s
public class Relation
{
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
public Int32?[] FindRelation(Relation[] relations)
{
List<Int32?> sourceIds = new List<int?>;
var countOfTargets = relations.Select(x => x.TargetId).Distinct().Count();
var relationsGroupedBySource = relations.GroupBy(x => x.SourceId);
foreach (var group in relationsGroupedBySource)
{
var distinctGroup = group.Distinct();
if (distinctGroup.Count() == countOfTargets)
{
sourceIds.Add(distinctGroup.Select(x => x.SourceId).First());
}
}
return sourceIds.ToArray();
}
public void Test()
{
Relation[] relations = {
new Relation() { SourceId = 1, TargetId = 1 },
new Relation() { SourceId = 1, TargetId = 2 },
new Relation() { SourceId = 2, TargetId = 1 },
new Relation() { SourceId = 3, TargetId = 2 }
};
var sourceIds = FindRelation(relations);
}
{
公共Int32源ID{get;set;}
public Int32 TargetId{get;set;}
}
公共Int32?[]查找关系(关系[]关系)
{
List sourceid=新列表;
var countOfTargets=relations.Select(x=>x.TargetId).Distinct().Count();
var relationsGroupedBySource=relations.GroupBy(x=>x.SourceId);
foreach(关系GroupedBySource中的var组)
{
var distinctGroup=group.Distinct();
if(distinctGroup.Count()=目标计数)
{
Add(distinctGroup.Select(x=>x.SourceId.First());
}
}
返回sourceIds.ToArray();
}
公开无效测试()
{
关系[]关系={
新关系(){SourceId=1,TargetId=1},
新关系(){SourceId=1,TargetId=2},
新关系(){SourceId=2,TargetId=1},
新关系(){SourceId=3,TargetId=2}
};
var sourceIds=FindRelation(关系);
}
?但如何使用GroupBy获取与所有TargetID相关的SourceID?使用GroupBy是我的第一个想法,但现在确定如何。。。也许我遗漏了什么。你说你需要一个LINQ答案,因为EF的使用,但是关系
不是IQueryable
,它是一个列表
,所以不涉及EF。我只需要使用Linq作为实体的查询framework@MiguelMoura然后,您应该更新问题和标记以反映这一点。是否可以在最后获得关系而不是SourceId?@MiguelMoura有to关系
匹配-(1,1)、(1,2)
。你想要哪一个?全部?如果可能的话,我希望两者都得到,因为SourceId=1与所有TargetId相关。我知道这些对(SourceId,TargetId)是唯一的。知道这一点是必要的,part.GroupBy(x=>x.SourceId,x=>x.TargetId)?@MiguelMoura我已经更新了我的答案。“编辑”部分中的代码应返回满足条件的所有关系。我只需要使用Linq,而不需要使用循环,因为我使用的是实体框架。对代码的解释将有助于OP和其他人更好地理解您的答案。仅仅发布你的代码会让其他人感到困惑。