我們經常在一個記憶體集合,比如List,根據某個或某些個屬性分組,統計顯示。最容易想到的方法便是,根據某個關鍵屬性,對List執行個體遍曆,轉化為如下字典類型
Dictionary<string, List<MyObject>
舉例,已知cars,
List<Car> cars = new List<Car>(){ new Car(1,"audiA6","private"), new Car(2,"futon","merchant"), new Car(3,"feiren","bike"), new Car(4,"bukon","private"), new Car(5,"baoma","private"), new Car(6,"dayun","merchant") };
想以id為鍵,值為Car轉化為一個字典idCarDict,除了遍曆這種邏輯最複雜,代碼需要最多的方法,我們還可以直接利用ToDictionary方法,
ar idCarDict = cars.ToDictionary(car=>car.id);
但是,這個方法是有局限的,關鍵碼對應的對象執行個體只能有一個,也就是返回的類型為,
Dictionary<string,Object>
這是糟糕的,因為可能一個關鍵碼對應多個執行個體,此時就得藉助GroupBy,先按關鍵碼分組後,然後再轉化為字典。
比如,我們想以type為鍵,得到這個車型下的多台汽車,
Dictionary<string, List<Car>> typeCarDict = cars.GroupBy(car => car.type).ToDictionary(g => g.Key, g => g.ToList());
這種轉化代碼簡潔,比以下遍曆邏輯好很多!
var dict = new Dictionary<string,List<Car>>();foreach(var car in cars){ if(dict.Contains(car.type)) dict[car.type].Add(car); else dict.Add(car.type,new List<Car>(){car}));}
這樣解決了一個關鍵碼對應多個執行個體的轉化,那麼根據多個關鍵碼的組合對應多個執行個體的問題,藉助List上的GroupBy能實現嗎? 不能實現。
這時候,需要寫Linq語句,將多個關鍵碼組合為一個新的對象,
new {key1, key2, ...}
舉一個列子,我們有這麼一個集合,集合中的元素是ValPair對象,這個對象包含兩個整形元素,Val1是小者,Val2相對大些。如何按照Val1,Val2的組合分組呢?
請看下面邏輯:
static void printfDuplicateCompare(List<ValPair> compares) { //按按鍵組合分組後,每組元素個數大於2的分組,按降序排序 var rtnByVal1 = from item in compares group item by new { item.Val1, item.Val2 } into g where g.Count()>1 orderby g.Count() descending select g; //按Val1和Val2組合為字典鍵,元素個數為值 var dict = rtnByVal1.ToDictionary(g => g.Key,g=>g.Count()); }
總結
List的GroupBy只能根據一個鍵分組,如果需要根據多個鍵組合分組,就得寫Linq語句組合。