Linq標準查詢操作符
Linq的出現讓代碼簡潔了不少。之前在項目中基本都在使用它,但是沒有完整的整理過,今天借這個周末,將其進行整理,方便後期對其的使用。Linq的操作可以分為聚合,連接,轉換,元素操作符,相等操作,生成,分組,分部,投影,數量,過濾,排序等,下面我們就通過實例的方式一一說下。
在具體實例之前先定義兩個集合供下面的使用和封裝的三個控制臺輸出方法:
1 List<string> words = new List<string>() { "zero", "one", "two", "three", "four" }; 2 List<int> numbers = new List<int>() { 0, 1, 2, 3, 4 };
1 static void Write(string name, object obj) 2 { 3 Console.WriteLine($"method:{name},\t result:{obj.ToString()}"); 4 } 5 6 static void Write(string title) 7 { 8 Console.WriteLine($"---------{title}-------------"); 9 } 10 11 static void Write() 12 { 13 Console.WriteLine($"-------------------------------"); 14 }
聚合
最常見的聚合操作符就是Aggregate,所有的其他聚合操作符都能表示為對Aggregate的調用,所有聚合操作符都使用立即執行的模式
1 Write("聚合操作");2 int sum = numbers.Sum(); 3 Write("sum", sum); 4 int count = numbers.Count; 5 Write("count", count); 6 double average = numbers.Average(); 7 Write("average", average); 8 long longCount = numbers.LongCount(x => x % 2 == 0); 9 Write("longCount", longCount); 10 int min = words.Min(p => p.Length); 11 Write("min", min); 12 int max = words.Max(p => p.Length); 13 Write("max", max); 14 string aggregate = numbers.Aggregate("seed", (current, item) => current + item, result => result.ToUpper()); 15 Write("aggregate", aggregate); 16 Write();
結果:
連接
1 Write("連接"); 2 List<int> concat = numbers.Concat(new List<int>() { 2, 3, 4, 5, 6 }).ToList(); 3 Write("concat", string.Join(",", concat)); 4 Write();
結果:
轉換
toArray和toList的含義顯而易見,他們讀取整個序列到內存中,並把結果作為一個數組或一個List<T>返回。兩者都是立即執行,cast和ofType把一個非類型化序列轉換為類型化序列的,或拋出異常(對於cast),或忽略那些不能隱式轉換為序列元素類型的輸入序列元素(對於ofType),這個運算符也能用於把某個類型化序列轉換為更加具體的類型化序列。轉換以流的形式延遲執行。ToDictionary和TolookUp都使用委托來獲得任何特定元素的鍵。執行模式為立即執行
1 Write("轉換"); 2 List<Object> allString = new List<Object>() { "These", "are", "all", "strings" }; 3 List<Object> notAllString = new List<Object>() { "Number", "at", "the", "end", 5 }; 4 5 IEnumerable<string> castOne = allString.Cast<string>(); 6 Write("castOne", string.Join(",", castOne)); 7 IEnumerable<string> ofTypeOne = allString.OfType<string>(); 8 Write("ofTypeOne", string.Join(",", ofTypeOne)); 9 10 IEnumerable<string> castTwo = notAllString.Cast<string>(); 11 Write("castOne", string.Join(",", castTwo));//遍歷時遇到轉換失敗的地方,會拋出異常 12 IEnumerable<string> ofTypeTwo = notAllString.OfType<string>(); 13 Write("ofTypeOne", string.Join(",", ofTypeTwo)); 14 15 int[] toArray = numbers.ToArray(); 16 List<int> toList = numbers.ToList(); 17 18 Dictionary<string, string> dictionary = words.ToDictionary(w => w.Substring(0, 2)); 19 ILookup<char, string> toLookUp = words.ToLookup(word => word[0]); 20 21 IDictionary<char, string> toDictionary = words.ToDictionary(p => p[0]);//異常:每個鍵只能有一個數據項,所以與遇到‘t’時轉換會異常 22 23 Write();
元素操作符
每個操作符都以同樣的方式執行,選取單個元素的簡化版本,就是在特定元素存在時返回他,不存在時就拋出一個異常,還有一個以orDefault結尾的版本,orDefault版本的功能完全一樣,只是在找不到想要的元素是,返回結果類型的默認值,而非拋出異常,但是有一種例外,如果序列為空,singleDefault將返回默認值,但是如果序列中的元素不止一個,將拋出異常,就像Single一樣.。所有操作符都是使用立即執行模式
1 var elementAt = words.ElementAt(2);//"Two" 2 var elementAtOrDefault = words.ElementAtOrDefault(10);//Null 3 var first = words.First();//Zero 4 var firstTwo = words.First(p => p.Length == 3);//one 5 // var firstThree = words.First(p=>p.Length==10);//異常 6 var firstOrDefault = words.FirstOrDefault(p => p.Length == 10);//Null 7 var last = words.Last();//four 8 var single = words.Single();//異常,不止一個元素 9 var singleDefault = words.SingleOrDefault();//異常,不止一個元素 10 var singleTwo = words.Single(p => p.Length == 5);//three 11 var singleThree = words.Single(p => p.Length == 10);//異常,沒有匹配的元素 12 var singleDefaultTwo = words.SingleOrDefault(P => P.Length == 10);//Nul
相等操作
按照順序逐一比較兩個序列中的元素是否相等,執行模式為立即執行
1 bool sequenceEqual = words.SequenceEqual(new List<string>() { "zero", "one", "two", "three", "four" });//true 2 bool sequenceEqualTwo = words.SequenceEqual(new List<string>() { "ZERO", "OME", "TWO", "THREE", "FOUR" });//false 3 bool sequenceEqualThree = words.SequenceEqual(new List<string>() { "ZERO", "OME", "TWO", "THREE", "FOUR" }, StringComparer.OrdinalIgnoreCase);//true
生成
在所有的生成操作符中,只有一個會對現有的序列進行處理:DefaultIfEmpty.如果序列不為空,就返回原始序列,否則返回含有但非我元素的序列。其中的元素通常是序列類型的默認值,不過重載方法允許你設定要使用的值.所有生成的操作符都是用延遲執行,並對結果進行流式處理。也就是說,他們不會預先生成集合並返回。不過,返回正確類型的空數組的empty方法是個例外。一個空的數組是完全不可變的,因此相同元素類型的所有元素類型的所有這種調用,都將返回相同的空數組。
1 var defaultIfEmpty = numbers.DefaultIfEmpty();//0,1,2,3,4 2 var defaultIfEmptyTwo = new int[0].DefaultIfEmpty();//0 3 var defaultIfEmptyThree = new int[0].DefaultIfEmpty(10);//0 4 var range = Enumerable.Range(15, 2);//15,16 5 var repeat = Enumerable.Repeat(25, 2);//25,25 6 IEnumerable<int> empty = Enumerable.Empty<int>();//一個類型為IEnumerable<int>的空序列
分組
1 IEnumerable<IGrouping<int, string>> groupby = words.GroupBy(p => p.Length); 2 IEnumerable<IGrouping<int, string>> groupTwo = words.GroupBy(p => p.Length, p => p.ToUpper()); 3 IEnumerable<string> groupThree = words.GroupBy(p => p.Length, (key, g) => key + ":" + g.Count());
結果:
投影
Select是一種簡單的從源元素到結果元素的一對一投影,selectMany在查詢表達式中有多個from子句的時候使用;原始序列中的每個元素都用來生成新的序列。兩個投影都是
延遲執行,.net 4 引入了一個新的操作符zip。它包含兩個序列,並對每個元素對應用指定的投影:先是每個序列的第一個元素,然後是每個序列的第二個元素,以此類推
任何一個源序列達到末尾時,結果序列都將停止產生。
1 IEnumerable<int> selectOne = words.Select(p => p.Length);//4,3,3,5,4 2 IEnumerable<string> selectTwo = words.Select((word, index) => index.ToString() + ":" + word);//0:zero,1:one .... 3 IEnumerable<char> selectMany = words.SelectMany(p => p.ToCharArray());//z,e,r,o,o... 4 IEnumerable<string> selectManyTwo = words.SelectMany((word, index) => Enumerable.Repeat(word, index)); 5 IEnumerable<string> zip = names.Zip(colors, (x, y) => x + "-" + y);
數量
數量操作符都返回一個boolean值,使用立即執行
1 bool allOne = words.All(p => p.Length > 3);//false 2 bool allTwo = words.All(p => p.Length > 2);//true 3 bool any = words.Any();//true 4 bool anyTwo = words.Any(p => p.Length == 6);//false 5 bool antThree = words.Any(p => p.Length == 5);//true 6 bool contains = words.Contains("FOUR");//false 7 bool containsTwo = words.Contains("FOUR", StringComparer.OrdinalIgnoreCase);//true
過濾
兩個過濾操作符where和ofType。where返回一個序列,where總是使用延遲執行和流式數據。
1 IEnumerable<string> where = words.Where(p => p.Length > 3);//zero,three,four 2 IEnumerable<string> whereTwo = words.Where((word, index) => index < word.Length);//one,two,three
基於集的操作符
把兩個序列作為元素的集合是很自然的。4個基於幾何的運算符都具有兩個重載方法,一個使用元素類型的默認相等比較,一個用於額外的參數中指定比較。所有的集合運算符都是延遲執行的
1 List<string> abbc = new List<string>() { "a", "b", "b", "c" }; 2 List<string> cd = new List<string>() { "c", "d" }; 3 4 var distinct = abbc.Distinct();//a,b,c 5 var intersect = abbc.Intersect(cd);//c 交集 6 var union = abbc.Union(cd);//a,b,c,d //並集 7 var expect = abbc.Except(cd);//a,b //差集 8 var exceptTwo = cd.Except(abbc);//d
排序
orderBy和OrderByDescending提供了主要的排序方式,thenBy 和ThenByDescending提供了次要排序方式。用以區別使用主要的排序方式無法區別的元素。在每種情況中,都要指定從元素到排序鍵的投影,也指定鍵之間的比較。linq排序比較穩定,即如果兩個元素根據他們的排序關鍵字被認為相等,那麽將按照他們原始序列中的順序返回
1 var orderBy = words.OrderBy(p => p);//four,one,three,two,zero 2 var orderByTwo = words.OrderBy(p => p[1]);//zero,three,one,four,two 3 var orderByThree = words.OrderBy(p => p.Length);//one,two,zero,four,three 4 var orderByDescending = words.OrderByDescending(p => p.Length);//three,zero,four,one,two 5 var orderByFour = words.OrderBy(p => p.Length).ThenBy(p => p);//one,two,four,zero,three 6 var orderByFive = words.OrderBy(p => p.Length).ThenByDescending(p => p);//two,one,zero,four,three 7 words.Reverse();//four,three,two,one,zero
Linq標準查詢操作符