如何解决如何在GroupBy中合并List <string>字段
我有一个Diff对象列表 看起来像这样
public class Diff
{
ChangeAction Action // ChangeAction is an Enum
string Type
DateTime StartDateTime
DateTime EndDateTime
int rateId
string rateDescription
List<string> properties
DayOfWeek day
List<DaysOfWeek> DaysOfWeek
DayOfWeek DayOfWeek
}
我的LINQ查询没有执行我认为会做的事情。我在diff.properties
的{{1}}中传入了GroupBy()
,它是一个列表,当列表中的所有字符串值都匹配时,我希望它分组
var results = diffs
.GroupBy(diff => new { diff.properties,diff.Action,diff.Type,diff.StartDateTime,diff.EndDateTime,diff.rateId,diff.rateDescription})
.Select(group => new Diff(
group.Key.Action,group.Key.ScheduleType,group.Key.StartDateTime,group.Key.EndDateTime,group.Key.rateId,group.Key.rateDescription,group.Key.properties,group
.Select(ts => ts.DayOfWeek)
.Distinct()
.OrderBy(dow => dow)
.ToList()))
.ToList();
results
和diffs
之间的唯一区别在于,以前存储在DayOfWeek
中的单数diffs
现在被放入复数DaysOfWeek
字段中(但列表中只有1个)。当前,results
和diffs
中的项目数相同。
我希望在结果列表中看到的是:
- 基于所有分组的匹配(包括diff.properties列表值)进行合并的较短列表
- 这还意味着DaysOfWeek列表中的一项以上。
我的问题是:
如何更改上面的LINQ查询以查看要在results
中看到的内容?
解决方法
您使用的匿名类型分组包含一个List<string>
,这导致您获得1-1个未分组的集合。
您需要
- 使用自定义类进行分组和重载
GetHashCode
和Equals
,如以下问题所示:Using LINQ GroupBy to group by reference objects instead of value objects
-或-
- 根据所选择的值(或其中的一个子集)组成一个字符串(
diff.properties,diff.Action,diff.Type,diff.startdatetime,diff.enddatetime,diff.rateId,diff.rateDescription
),该字符串将用作与之分组的唯一键
您的GroupBy
属性中有一些是引用类型,而这些类型的默认比较器是引用比较,因此这些匹配都不会匹配。为了克服这个问题,我们可以为EqualityComparer
类编写自己的Diff
,以便我们可以用自己的方式比较它们:
public class DiffEqualityComparer : IEqualityComparer<Diff>
{
public bool Equals(Diff first,Diff second)
{
if (first == null || second == null) return ReferenceEquals(first,second);
if (first.Properties == null && second.Properties != null) return false;
if (first.Properties != null && second.Properties == null) return false;
if (first.Properties != null && second.Properties != null &&
!first.Properties.OrderBy(p => p)
.SequenceEqual(second.Properties.OrderBy(p => p)))
return false;
if (!first.Action.Equals(second.Action)) return false;
if (!string.Equals(first.Type,second.Type)) return false;
if (!first.Start.Equals(second.Start)) return false;
if (!first.End.Equals(second.End)) return false;
if (!first.RateId.Equals(second.RateId)) return false;
if (!string.Equals(first.RateDescription,second.RateDescription)) return false;
return true;
}
public int GetHashCode(Diff obj)
{
var hash = obj.Properties?.Aggregate(0,(accumulator,current) => accumulator * 17 + current.GetHashCode()) ?? 0;
hash = hash * 17 + obj.Action.GetHashCode();
hash = hash * 17 + obj.Type?.GetHashCode() ?? 0;
hash = hash * 17 + obj.Start.GetHashCode();
hash = hash * 17 + obj.End.GetHashCode();
hash = hash * 17 + obj.RateId.GetHashCode();
hash = hash * 17 + obj.RateDescription?.GetHashCode() ?? 0;
return hash;
}
}
最后,我们可以在GroupBy
方法中使用此自定义比较器:
var results = diffs
.GroupBy(diff => new DiffEqualityComparer())
.Select( // rest of code omitted
,
我解决了!
阅读another question以及该问题的评论和答案帮助我弄清楚了!
public class DiffComparer : IEqualityComparer<Diff>
{
public bool Equals(Diff x,Diff y)
{
return x.Action == y.Action &&
x.Type == y.Type &&
x.StartDateTime == y.StartDateTime &&
x.EndDateTime == y.EndDateTime &&
x.rateId== y.rateId &&
x.rateDescription == y.rateDescription &&
x.properties.SequenceEqual(y.properties);
}
public int GetHashCode(Diff x)
{
int hash = 17;
hash = hash * 23 + x.Action.GetHashCode();
hash = hash * 23 + x.Type.GetHashCode();
hash = hash * 23 + x.StartDateTime .GetHashCode();
hash = hash * 23 + x.EndDateTime.GetHashCode();
hash = hash * 23 + x.rateId.GetHashCode();
hash = hash * 23 + x.rateDescription.GetHashCode();
foreach (string prop in x.properties)
{
hash = hash * 31 + prop.GetHashCode();
}
return hash;
}
}
我对LINQ进行了编辑:
var results = diffs
.GroupBy(diff => diff,new DiffComparer())
.Select(group => new Diff(
group.Key.Action,group.Key.ScheduleType,group.Key.StartDateTime,group.Key.EndDateTime,group.Key.rateId,group.Key.rateDescription,group.Key.properties,group
.Select(ts => ts.DayOfWeek)
.Distinct()
.OrderBy(dow => dow)
.ToList()))
.ToList();
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。