2014-10-31 60 views
1

我按多列對一個集合進行分組。LINQ將多列與嵌套集合分組

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,或者一個簡單的方法來解決這個問題。

編輯: 解釋更多預期內容。作爲分組的結果,我希望擁有共享相同PassengerNameRecord的airProducts的集合,並且屬於給定空中產品的航班共享相同的MarketingAirlineCode,FlightNo,DepartureDate。我知道如何通過奉承PassengerNameRecord的集合來實現它,所以航班包含在其中,將其分組,所以我有一組共享分組屬性的空氣產品。然後重建受寵若驚的結構。我希望有一種方法可以通過遍歷一些集合來添加groupBy屬性,或者有一種方法來合併分組集合 - 如果有一種方法可以按PassengerNameRecord對集合進行分組,並將集合按照飛行屬性進行分組併合並他們在一起,不幸的是我懷疑有一種簡單的方法來做這種合併。

+1

的「易集團」雙組分不能編譯。您需要使用匿名類型。 – 2014-10-31 10:01:49

+0

所以基本上你想通過一個集合(+ PassengerNameRecord)進行分組?創建一個實現'IEqualityComparer '的類,並帶有適當的'GetHashCode'和'Equals'。 'T'是單個'airproductsPerClient'的類型。 – 2014-10-31 10:06:11

+0

我不確定你瞭解分組是如何工作的 - 它應該將任何給定的實體放入一個組中。在你的例子中,給定多個航班,你可能會得到多個組,同一個實體應該被分配 - 這不再是分組(因此你可能想提供一些關於這應該如何工作的更多信息)。 – decPL 2014-10-31 10:10:18

回答

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

這是解決問題的非常好的方法。感謝一百萬的解決方案。 – 2014-10-31 11:25:32

0

在這種情況下,您需要從內部表開始。 內部表也需要外部表的引用,這樣就像你有一個

ICollection<Flight> FlightsAirProduct

你還需要一個Airproduct會員Flight內。

然後組機票這樣的(僞代碼)

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