我有以下课程:
public class Relation {
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
以及以下列表:
List<Relation> relations = service.GetRelations();
我需要选择与所有目标相关的SourceId。
因此,给出以下带有对(SourceId, TargetId)
的示例:
(1, 1), (1, 2), (2, 1), (3, 2)
在这种情况下,TargetId
可以是1或2。
与所有SourceId
相关的唯一TargetIds (1, 2)
是SourceId 1
。
SourceId 2
仅与TargetId 1
相关,而SourceId 3
仅与TargetId 2
相关。
我该怎么做?
答案 0 :(得分:1)
您需要收集所有可能的目标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
中是否存在所有组成员:
var result = input.GroupBy(x => x.SourceId, x => x.TargetId)
.Where(g => allTargetId.All(x => g.Contains(x)))
.Select(g => g.Key)
.ToArray();
注意:为使此代码正常工作,我向您的Relation
类添加了一个构造函数,看起来像
public class Relation
{
public Relation(int sourceId, int targetId)
{
SourceId = sourceId;
TargetId = targetId;
}
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
要获取Relation
,可以使用以下查询:
var result = input.GroupBy(x => x.SourceId)
.Where(g => allTargetId.All(x => g.Select(y => y.TargetId).Contains(x)))
.SelectMany(g => g)
.ToArray();
请注意,我仅使用linq2objects对其进行了测试,所以我不确定如何将其转换为SQL
答案 1 :(得分:0)
以下代码完成了您所要求的。它具有单元测试的形式,因此您可以检查不同的情况
[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());
}
我基本上做到了:
dict
变量)答案 2 :(得分:0)
一种简单的方法是将记录按*v.begin() = *(v.end() - 2)
分组,然后找到所有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));
}
的末尾将包含与所有set
相关的所有SourceId
答案 3 :(得分:0)
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);
}