【问题标题】:How to incorporate List<string> field in GroupBy()如何在 GroupBy() 中合并 List<string> 字段
【发布时间】:2020-08-19 08:34:08
【问题描述】:

我有一个 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 查询没有按照我认为的那样执行。我在GroupBy() 中传入diff.properties,这是一个列表,我希望它在列表中的所有字符串值都匹配时进行分组

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();

resultsdiffs 之间的唯一区别在于,以前存储在 diffs 中的单数 DayOfWeek 现在被放入复数 DaysOfWeek 字段(但列表中只有一项)。目前,resultsdiffs 中的项目数量相同。

我希望在结果列表中看到的是:

  1. 一个较短的列表,基于对所有分组(包括 diff.properties 列表值)的匹配进行合并
  2. 这也意味着 DaysOfWeek 列表中有超过 1 个项目。

我的问题是:

如何更改上面的 LINQ 查询以查看我想在 results 中看到的内容?

【问题讨论】:

  • @Enigmativity - 你误解了这个问题吗?
  • @Enigmativity 我刚才在底部添加了我的问题,谢谢
  • @TravisJ - 不,但 OP 最初只是给出了一系列声明。他们没有解释他们被困在哪里,他们做了什么尝试,或者明确地问我们他们需要我们什么。复习一下How to Ask 可能会有用。
  • 如果你在Diff 中覆盖Equals,这个问题会更容易解决。
  • 您的一个GroupBy 属性(diff.properties) 是List&lt;string&gt;List&lt;T&gt; 的默认比较器是参考比较,因此在这种情况下没有两个列表会匹配。您需要为Diff 类编写自己的比较器,您可以在其中使用.SequenceEqual 来确定@​​987654344@ 中的strings 之间的相等性。可能同样的事情也适用于Action 属性。

标签: c# .net linq


【解决方案1】:

您与匿名类型一起使用的分组包含 List&lt;string&gt;,这会导致您获得 1-1 未分组集。

你需要

- 或-

  • 从被选中的值或其中的子集组成一个字符串 (diff.properties, diff.Action, diff.Type, diff.startdatetime, diff.enddatetime, diff.rateId, diff.rateDescription),作为分组的唯一键

【讨论】:

  • 如果我想通过使用new {...} 来保持匿名分组,那么我是否想要覆盖仅包含这些字段的 Equals() 和 GetHashCode()(因为我只想按这些字段进行分组)?
【解决方案2】:

您的一些GroupBy 属性是引用类型,这些类型的默认比较器是引用比较,因此这些都不会匹配。为了克服这个问题,我们可以为Diff 类编写自己的EqualityComparer,以便我们以自己的方式比较它们:

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 

【讨论】:

  • 酷,感谢这个例子! ChangeAction 是一个枚举,我上面的答案似乎在没有为 ChangeAction 实现 Equals() 和 GetHashCode() 的情况下工作。那是因为它是一个枚举吗?
  • 是的!我没有看到你的答案,很高兴你知道了!
  • 太棒了!我会在我的帖子中说明 ChangeAction 是一个枚举 :) 谢谢!
【解决方案3】:

我解决了!

阅读another question 和这个问题中的 cmets + 答案帮助我弄清楚了!

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();


【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 2010-10-17
    • 2018-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多