【问题标题】:C# Group By Several Nested Properties And List valuesC# 按多个嵌套属性和列表值分组
【发布时间】:2016-02-22 01:47:39
【问题描述】:

我有这个对象结构:

public class Root
{
public int Value1;
public int Value2;
public List<NestedA> NestedAList;
}

public class NestedA
{
public List<NestedB> NestedBList;
public List<NestedC> NestedCList;
}

public class NestedB{
 public int ValueB;
 public int ValueB2;
}

public class NestedC{
 public int ValueC;
 public int ValueC2;
}

我需要使用 Root 类中的所有值和它的嵌套列表对根对象进行分组。 我已经玩了一段时间了,不知道如何/或我是否可以在单个组中按语句执行此操作,或者完成此操作的最佳方法可能是什么。

编辑:我需要按根属性、嵌套 A 属性、嵌套 B 属性和嵌套 C 属性分组的项目。 所以这是有道理的:我的真实对象有更多属性,只是显示我需要分组的那些,并且可以用作起点。

提前致谢。

如果我们有这个元素

Root
Value1 = 1
Value2 = 2
NestedAList = [
    {NestedBList = [
        {ValueB=2, ValueB2=3}
    ]
    NestedCList = [
        {ValueC=5, ValueC2=11}
    ]}
]

它应该与这个分组:

Root
Value1 = 1
Value2 = 2
NestedAList = [
    {NestedBList = [
        {ValueB=2, ValueB2=3}
    ]
    NestedCList = [
        {ValueC=5, ValueC2=11}
    ]}
]

但不是这个:

Root
Value1 = 1
Value2 = 2
NestedAList = [
    {NestedBList = [
        {ValueB=2, ValueB2=3}, { ValueB= 1, ValueB2=4}
    ]
    NestedCList = [
        {ValueC=5, ValueC2=11}
    ]}
]

【问题讨论】:

  • 你能展示一下简单的输入和输出吗?你想按哪个属性分组?你想解开嵌套列表吗?不清楚。
  • 我建议你看看这个问题。也许这就是你所需要的.. stackoverflow.com/questions/5231845/…
  • 那一个是使用多个列并将组选择到一个新的组中,我需要使用列表值进行分组。我确实尝试使用那里的一些想法进行分组,但是无法成功。

标签: c# list grouping


【解决方案1】:

要完成此任务,您可以为层次结构中的每个类覆盖 Equals()GetHashCode() 方法。这可能有点棘手,例如,像这样:

public class Root
{
    public int Value1;
    public int Value2;
    public List<NestedA> NestedAList;

    public override bool Equals(object obj)
    {
        Root other = obj as Root;
        if (other == null) return false;
        return this.Value1 == other.Value1 && this.Value2 == other.Value2 && this.NestedAList.SequenceEqual(other.NestedAList);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hasha = 19;
            foreach (NestedA na in NestedAList)
            {
                hasha = hasha * 31 + na.GetHashCode();
            }

            return (Value1 ^ Value1 ^ hasha).GetHashCode();
        }               
    }
}

public class NestedA
{
    public List<NestedB> NestedBList;
    public List<NestedC> NestedCList;

    public override bool Equals(object obj)
    {
        NestedA other = obj as NestedA;
        if (other == null) return false;

        return NestedBList.SequenceEqual(other.NestedBList) && NestedCList.SequenceEqual(other.NestedCList);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hashb = 19;
            foreach (NestedB nb in NestedBList)
            {
                hashb = hashb * 31 + nb.GetHashCode();
            }
            int hashc = 19;
            foreach (NestedC nc in NestedCList)
            {
                hashc = hashc * 31 + nc.GetHashCode();
            }
            return (hashb ^ hashc).GetHashCode();
        }            
    }
}

public class NestedB{
     public int ValueB;
     public int ValueB2;

     public override bool Equals(object obj)
     {
         NestedB other = obj as NestedB;
         if (other == null) return false;
         return this.ValueB == other.ValueB && this.ValueB2 == other.ValueB2;
     }

     public override int GetHashCode()
     {
         return (ValueB ^ ValueB2).GetHashCode();
     }
}

public class NestedC{
     public int ValueC;
     public int ValueC2;

     public override bool Equals(object obj)
     {
         NestedC other = obj as NestedC;
         if (other == null) return false;
         return this.ValueC == other.ValueC && this.ValueC2 == other.ValueC2;
     }

     public override int GetHashCode()
     {
         return (ValueC ^ ValueC2).GetHashCode();
     }
}

之后,您可以轻松选择唯一的根(每个唯一的根代表一个组):

roots.Distinct().ToList()

使用GoupBy() 的结果相同:

roots.GroupBy(r => r).Select(g => g.First()).ToList()

计算每组中的元素:

roots.GroupBy(r => r).Select(g => g.Count())

枚举第一组中的元素:

roots.GroupBy(r => r).First().Select(g => g)

如果您不关心列表中的元素顺序,请使用 Enumerable.All 而不是 SequenceEqual

编辑:另外,在这种情况下,您必须更改哈希码生成算法。例如,像这样:hashb = hashb + nb.GetHashCode() * 31;(有关可能算法的附加信息here

【讨论】:

  • 我现在正走这条路,会尝试这个解决方案并告诉你。
  • 感谢成功。不得不更改哈希码生成,因为我不关心列表中的元素顺序,所以我以这种方式结束生成代码,例如: hashb = hashb + nb.GetHashCode() * 31;.
  • 不客气。我已根据您的评论更新了我的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 2019-07-29
  • 1970-01-01
相关资源
最近更新 更多