Группа C # по нескольким вложенным свойствам и значениям списка

У меня есть такая структура объекта:

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;
}

Мне нужно сгруппировать корневые объекты, используя все значения из корневого класса и его вложенных списков. Я некоторое время играл и не могу понять, как это сделать / или могу ли я сделать это в одной группе по заявлению, или какой лучший подход к этому может быть.

Изменить: мне нужны элементы, сгруппированные по корневым свойствам, вложенным свойствам 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}
    ]}
]

person Mg.    schedule 19.11.2015    source источник
comment
не могли бы вы показать простой ввод и вывод? вы хотите сгруппировать по какому именно свойству? вы хотите развернуть вложенные списки? не ясно.   -  person M.kazem Akhgary    schedule 19.11.2015
comment
Предлагаю вам проверить этот вопрос. Может быть, это то, что вам нужно .. stackoverflow.com/questions/5231845/   -  person Rodrigo Vedovato    schedule 19.11.2015
comment
Этот использует несколько столбцов и выбирает группу в новую, мне нужно сгруппировать, используя значения списка. Я попытался сгруппировать, используя некоторые идеи оттуда, но не смог заставить это работать.   -  person Mg.    schedule 19.11.2015


Ответы (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; (дополнительная информация о возможных алгоритмах здесь)

person Igor Bendrup    schedule 19.11.2015
comment
Я шел по этому пути прямо сейчас, попробую это решение и дам вам знать. - person Mg.; 20.11.2015
comment
Спасибо, это удалось. Пришлось изменить генерацию хэш-кода, так как меня не заботил порядок элементов в списке, поэтому я закончил генерировать коды таким образом, например: hashb = hashb + nb.GetHashCode () * 31 ;. - person Mg.; 20.11.2015
comment
Добро пожаловать. Я обновил свой ответ в соответствии с вашим комментарием - person Igor Bendrup; 21.11.2015