LINQ группирует несколько столбцов с вложенной коллекцией

1

Я группирую коллекцию по нескольким столбцам. Их легко группировать, если они находятся на том же уровне гнездования:

var groupedAirProducts = airproductsPerClient.GroupBy(ac => new
{
    ac.AirProduct.PassengerNameRecord,
    ac.AirProduct.Flights.First().MarketingAirlineCode,
    ac.AirProduct.Flights.First().FlightNo,
    ac.AirProduct.Flights.First().DepartureDate
})

Проблема в том, что я не хочу группироваться только по первому рейсу, но я хочу включить все рейсы. То, что я хотел бы сделать, это что-то вроде:

var groupedAirProducts= airproductsPerClient.GroupBy(ac =>
{
    ac.AirProduct.PassengerNameRecord,
    foreach(var flight in ac.AirProduct.Flights){
        flight.MarketingAirlineCode,
        flight.FlightNo,
        flight.DepartureDate
    }
})

Обратите внимание, что приведенный выше код является лишь иллюстрацией идеи. Это не рабочий/правильный код. Единственный способ, которым я знаю, как это сделать, довольно уродливый и сложный. Мне было интересно, есть ли хороший способ сделать это с помощью LINQ или простой способ решить эту проблему.

Изменение: объяснить больше того, что ожидается. В результате группировки я хочу иметь коллекции airProducts, которые используют один и тот же PassengerNameRecord, и что полеты, принадлежащие данному воздушному продукту, имеют одинаковый маркетингAirlineCode, FlightNo, DepartureDate. Я знаю, как реализовать его, льстив коллекции PassengerNameRecord, поэтому в нее включены рейсы, группируя их, поэтому у меня есть группы воздушных продуктов, которые разделяют сгруппированные свойства. А затем перестроить лестную структуру. Я надеялся, что есть способ либо добавить свойства groupBy, итерируя через некоторую коллекцию, либо есть способ объединить сгруппированную коллекцию - если есть способ собрать коллекцию с помощью PassengerNameRecord, а сбор, сгруппированный по свойствам Flight и слиянием их вместе, к сожалению, я сомневаюсь, что есть простой способ сделать такое слияние.

  • 1
    Часть "easy to group" не компилируется. Вам нужно использовать анонимный тип.
  • 0
    Так в принципе вы хотите сгруппировать по коллекции (+ PassengerNameRecord )? Создайте класс, который реализует IEqualityComparer<T> с правильным GetHashCode и Equals . T - это тип одного airproductsPerClient .
Показать ещё 2 комментария
Теги:
linq

2 ответа

1
Лучший ответ

Вы можете реализовать пользовательский IEqualityComparer<AirClient> для GroupBy (или других методов LINQ).

Вы можете реализовать его следующим образом:

public class AirClientComparer : IEqualityComparer<AirClient>
{
    public bool Equals(AirClient lhs, AirClient rhs)
    {
        if (lhs == null || rhs == null) return false;
        if(object.ReferenceEquals(lhs, rhs)) return true;
        if(lhs.PassengerNameRecord != rhs.PassengerNameRecord) return false;
        if(object.ReferenceEquals(lhs.AirProduct, rhs.AirProduct)) return true;
        if(lhs.AirProduct == null || rhs.AirProduct == null) return false;
        if(object.ReferenceEquals(lhs.AirProduct.Flights , rhs.AirProduct.Flights )) return true;
        if(lhs.AirProduct.Flights.Count !=  rhs.AirProduct.Flights.Count) return false;
        if(lhs.AirProduct.Flights.Count == 0 && rhs.AirProduct.Flights.Count == 0) return true;
        return lhs.AirProduct.Flights.All(f =>
            rhs.AirProduct.Flights.Any(f2 =>
                    f.MarketingAirlineCode == f2.MarketingAirlineCode
                 && f.FlightNo == f2.FlightNo
                 && f.DepartureDate == f2.DepartureDate));
    }

    public int GetHashCode(AirClient obj)
    {
        if(obj.AirProduct == null) return 0;
        int hash = obj.AirProduct.PassengerNameRecord == null 
                  ? 17 : 17 * obj.AirProduct.PassengerNameRecord.GetHashCode();
        unchecked
        {
            foreach(var flight in obj.AirProduct.Flights)
            {
                hash = (hash * 31) + flight.MarketingAirlineCode == null ? 0 : flight.MarketingAirlineCode.GetHashCode();
                hash = (hash * 31) + flight.FlightNo == null ? 0 : flight.FlightNo.GetHashCode();
                hash = (hash * 31) + flight.DepartureDate.GetHashCode();
            }
        }
       return hash;
    }
}

Теперь вы можете использовать его, например, в GroupBy:

var groupedAirProducts = airproductsPerClient.GroupBy(ac => new AirClientComparer());
  • 0
    Это действительно хороший способ решения проблемы. Спасибо миллион за решение.
0

В таких случаях вам нужно начать с внутренней таблицы. Внутренняя таблица также нуждается в ссылке на внешнюю таблицу, например, у вас есть

ICollection<Flight> Flights в AirProduct

вам также нужен член Airproduct внутри Flight.

Затем группируйте свои полеты следующим образом (псевдокод)

AirProduct.Flights.groupby( flight => new{ flight.MarketingAirlineCode,
        flight.FlightNo,
        flight.DepartureDate,
        flight.product.PassengerNameRecord
});

Ещё вопросы

Сообщество Overcoder
Наверх
Меню