使用逻辑或对多个属性进行分组
Group Multiple Properties with Logical OR
我有一个 class 具有多个属性,我对其中两个感兴趣。例如,在下面的示例中 PropA
和 PropB
。
public class GroupByOR
{
public string PropA { get; set; }
public string PropB { get; set; }
public int SomeNumber { get; set; }
public GroupByOR(string a, string b, int num) { PropA = a; PropB = b; SomeNumber = num; }
}
我想对这个 class' 对象的列表进行分组,如果 either PropA
或者PropB
匹配。
例如,假设我的列表如下所示:
List<GroupByOR> list = new List<GroupByOR>
{
new GroupByOR("CA", "NY", 1), // Item 1
new GroupByOR("CA", "OR", 2), // Item 2
new GroupByOR("NY", "OR", 5) // Item 3
};
那么我想要的结果是这样的:
Group 1: Items 1 and 2 (based on CA)
Group 2: Items 1 and 3 (based on NY)
Group 3: Items 2 and 3 (based on OR)
环顾四周,我发现了 this 和许多其他示例,但它们似乎都专注于按多个属性进行分组,但使用 AND
操作。
我想要实现的目标是否可行?
否则 join
是去这里的路吗?如果是这样,你能给我指明正确的方向吗?
您最终会得到比开始时更多的项目,因此 GroupBy 并不是全部答案。你需要这样的东西:
List<GroupByOR> list = new List<GroupByOR>
{
new GroupByOR("CA", "NY", 1), // Item 1
new GroupByOR("CA", "OR", 2), // Item 2
new GroupByOR("NY", "OR", 5) // Item 3
};
var lookupA = list.ToLookup(e => e.PropA);
var lookupB = list.ToLookup(e => e.PropB);
var keys = lookupA.Select(e => e.Key)
.Concat(lookupB.Select(e => e.Key)).Distinct();
var result = keys.Select(e =>
new
{
Key = e,
Values = lookupA[e].Concat(lookupB[e]).Distinct()
});
这是将结果投影到一个新的匿名类型中,Key 是 PropA 或 PropB 的值,Values 是所有匹配元素的 IEnumerable。
编辑:代码演练
前两行 linq 行使用给定的键从枚举中进行查找(实际上是一个多值字典)。这些可以枚举为 IEnumerable>,但也可以用于高效查找。
var lookupA = list.ToLookup(e => e.PropA);
var lookupB = list.ToLookup(e => e.PropB);
下一行是查找 PropA 和 PropB 的所有不同值(使用查找,但也可以为此返回列表)。
var keys = lookupA.Select(e => e.Key).Concat(lookupB.Select(e => e.Key)).Distinct();
最后一行采用不同的键,从 propA 查找和 propB 查找中获取匹配的枚举,然后将它们连接起来,并且(现在我发现了另一个错误)对它们进行去重。
select 语句正在生成匿名类型 - 这些类型不能明确引用,但可以分配给 var 并可以枚举它们。如果要存储结果值,则必须创建非匿名类型。
var result = keys.Select(e =>
new
{
Key = e,
Values = lookupA[e].Concat(lookupB[e]).Distinct()
});
编辑:输出
CA
Values: (PropA: CA, PropB: NY, SomeNumber: 1) (PropA: CA, PropB: OR, SomeNumber: 2)
NY
Values: (PropA: NY, PropB: OR, SomeNumber: 5) (PropA: CA, PropB: NY, SomeNumber: 1)
OR
Values: (PropA: CA, PropB: OR, SomeNumber: 2) (PropA: NY, PropB: OR, SomeNumber: 5)
我有一个 class 具有多个属性,我对其中两个感兴趣。例如,在下面的示例中 PropA
和 PropB
。
public class GroupByOR
{
public string PropA { get; set; }
public string PropB { get; set; }
public int SomeNumber { get; set; }
public GroupByOR(string a, string b, int num) { PropA = a; PropB = b; SomeNumber = num; }
}
我想对这个 class' 对象的列表进行分组,如果 either PropA
或者PropB
匹配。
例如,假设我的列表如下所示:
List<GroupByOR> list = new List<GroupByOR>
{
new GroupByOR("CA", "NY", 1), // Item 1
new GroupByOR("CA", "OR", 2), // Item 2
new GroupByOR("NY", "OR", 5) // Item 3
};
那么我想要的结果是这样的:
Group 1: Items 1 and 2 (based on CA)
Group 2: Items 1 and 3 (based on NY)
Group 3: Items 2 and 3 (based on OR)
环顾四周,我发现了 this 和许多其他示例,但它们似乎都专注于按多个属性进行分组,但使用 AND
操作。
我想要实现的目标是否可行?
否则 join
是去这里的路吗?如果是这样,你能给我指明正确的方向吗?
您最终会得到比开始时更多的项目,因此 GroupBy 并不是全部答案。你需要这样的东西:
List<GroupByOR> list = new List<GroupByOR>
{
new GroupByOR("CA", "NY", 1), // Item 1
new GroupByOR("CA", "OR", 2), // Item 2
new GroupByOR("NY", "OR", 5) // Item 3
};
var lookupA = list.ToLookup(e => e.PropA);
var lookupB = list.ToLookup(e => e.PropB);
var keys = lookupA.Select(e => e.Key)
.Concat(lookupB.Select(e => e.Key)).Distinct();
var result = keys.Select(e =>
new
{
Key = e,
Values = lookupA[e].Concat(lookupB[e]).Distinct()
});
这是将结果投影到一个新的匿名类型中,Key 是 PropA 或 PropB 的值,Values 是所有匹配元素的 IEnumerable
编辑:代码演练
前两行 linq 行使用给定的键从枚举中进行查找(实际上是一个多值字典)。这些可以枚举为 IEnumerable
var lookupA = list.ToLookup(e => e.PropA);
var lookupB = list.ToLookup(e => e.PropB);
下一行是查找 PropA 和 PropB 的所有不同值(使用查找,但也可以为此返回列表)。
var keys = lookupA.Select(e => e.Key).Concat(lookupB.Select(e => e.Key)).Distinct();
最后一行采用不同的键,从 propA 查找和 propB 查找中获取匹配的枚举,然后将它们连接起来,并且(现在我发现了另一个错误)对它们进行去重。
select 语句正在生成匿名类型 - 这些类型不能明确引用,但可以分配给 var 并可以枚举它们。如果要存储结果值,则必须创建非匿名类型。
var result = keys.Select(e =>
new
{
Key = e,
Values = lookupA[e].Concat(lookupB[e]).Distinct()
});
编辑:输出
CA
Values: (PropA: CA, PropB: NY, SomeNumber: 1) (PropA: CA, PropB: OR, SomeNumber: 2)
NY
Values: (PropA: NY, PropB: OR, SomeNumber: 5) (PropA: CA, PropB: NY, SomeNumber: 1)
OR
Values: (PropA: CA, PropB: OR, SomeNumber: 2) (PropA: NY, PropB: OR, SomeNumber: 5)