(一)概述 數組的大小是固定的。如果元素個數是動態的,就應使用集合類。 List<T>是與數組相當的集合類。還有其它類型的集合:隊列、棧、鏈表、字典和集。 (二)列表 1、創建列表 調用預設的構造函數,就可以創建列表對象。在泛型類List<T>中,必須為聲明為列表的值指定類型。使用預設構造函數創建一 ...
(一)概述
數組的大小是固定的。如果元素個數是動態的,就應使用集合類。
List<T>是與數組相當的集合類。還有其它類型的集合:隊列、棧、鏈表、字典和集。
(二)列表
1、創建列表
調用預設的構造函數,就可以創建列表對象。在泛型類List<T>中,必須為聲明為列表的值指定類型。使用預設構造函數創建一個空列表。元素添加到列表後,列表的容量會擴大,每次添加元素達到容量上限後,容量將重新設置為原來的2倍。
例子:
List<string> strList = new List<string>();
如果列表的容量改變了,整個集合就要重新分配到一個新的記憶體塊中。使用Capacity屬性可以獲取和設置集合的容量。
例子:
strList.Capacity = 100;
集合中的元素個數可以用Count屬性讀取。
例子:
var count= strList.Count;
可以調用TrimExcess()方法去除不需要的容量。
例子:
strList.TrimExcess();
但要註意的是,元素個數超過容量的90%,TrimExcess()方法就什麼都不做。
(1)集合初始值設定項
還可以使用集合初始值設定項給集合賦值。
例子:
List<string> strList = new List<string>() { "zhangsan", "lisi" };
(2)添加元素
使用Add()方法可以給列表添加元素。
例子:
strList.Add("zhangsan");
使用AddAange()方法,可以一次性給集合添加多個元素。
例子:
strList.AddRange(new string[] { "lisi", "wangmazi" }); strList.AddRange(new List<string> { "zhaoliu", "qianqi" });
(3)插入元素
使用Insert()方法可以在指定位置插入元素。
例子:
strList.Insert(0, "begin");
使用InsertRange()提供了插入大量元素的功能。
例子:
strList.InsertRange(1, new string[] { "zhang", "li", "wang" });
(4)訪問元素
實現了IList<T>和IList介面的所有類都提供了一個索引器,可以使用索引器,通過傳遞元素號來訪問元素。
例子:
var str0 = strList[0];
處理使用foreach語句進行遍歷以外,List<T>類還提供了了ForEach()方法,該方法返回void,參數為Action<T>。ForEach()方法遍歷集合中的每一項,調用作為每一項的參數傳遞的方法。
例子:
List<string> strList = new List<string>(); strList.Add("zhangsan"); strList.AddRange(new string[] { "lisi", "wangmazi" }); strList.AddRange(new List<string> { "zhaoliu", "qianqi" }); strList.ForEach(Console.WriteLine); Console.ReadKey();
運行以上代碼,結果如下:
將Console.WriteLine()方法作為參數傳遞給ForEach()方法。
(5)刪除元素
刪除元素時,可以利用索引,也可以傳遞要刪除的元素。
例子:
strList.RemoveAt(1);
按索引刪除比較快。
RemoveRange()方法可以從集合中刪除許多元素。
strList.RemoveRange(0, 1);
還可以使用RemoveAll()方法刪除有指定特定的所有元素,還可以使用ICollection<T>介面定義的Clear()方法。
(6)搜索
可以使用IndexOf()、LastIndexOf()、FindIndex()、FindLastIndex()、Find()、FindLast()。如果只檢查元素是否存在,List<T>類提供了Exists()方法。
例子:
int index = strList.IndexOf("lisi");
(7)排序
List<T>類可以使用Sort()方法對元素排序。Sort()方法使用快速排序演算法,比較所有的元素,值到整個列表排好序位為止。
(8)類型轉換
使用List<T>類的ConvertAll<TOutput>()方法,可以把所有類型的集合轉換為另一種類型。
例子:
List<object> objList = strList.ConvertAll<object>(s => s);
2、只讀集合
List<T>集合中的AsReadOnly()方法返回ReadOnlyCollection<T>類型的對象。
(三)隊列
隊列(Queue<T>)是已先進先出(FIFO)的方式來處理的集合。隊列只允許在隊列中添加元素,該元素會放在隊列的末尾(Enqueue()方法),從隊列頭部獲取元素(使用Dequeue()方法)。
例子:
Queue<string> qu = new Queue<string>(); qu.Enqueue("zhangsan"); qu.Enqueue("lisi"); qu.Enqueue("wangmazi"); var dqu = qu.Dequeue(); Console.WriteLine(dqu);
運行以上代碼,結果如下:
需要註意的是Dequeue()方法獲取元素後會從隊列中刪除該元素,使用Peek()方法則僅獲取不刪除。使用枚舉器不會改變元素的狀態。因為Queue<T>類沒有實現IList<T>介面,所以不能用索引器訪問隊列。
(四)棧
棧(Stack<T>)與隊列(Queue<T>)很相似,只是最後添加到棧中的元素最先讀取。棧是一個後進先出(LIFO)的容器。棧用Push()方法添加元素,用Pop()方法獲取最近的元素。
例子:
Stack<string> st = new Stack<string>(); st.Push("zhangsan"); st.Push("lisi"); st.Push("wangmazi"); var pst = st.Pop(); Console.WriteLine(pst);
運行以上代碼,結果如下:
需要註意的是Pop()方法獲取元素後會從隊列中刪除該元素,使用Peek()方法則僅獲取不刪除。使用枚舉器不會改變元素的狀態。
(五)鏈表
LinkedList<T>是一個雙向鏈表,其元素指向它前面和後面的元素。鏈表的優點是,插入列表中間位置會很快。缺點是只能一個一個訪問。鏈表不能在列表中僅存儲值,其還會包含上一個和下一個元素的信息。
LinkedList<T>類定義的成員可以訪問鏈表中的第一個和最後一個元素(First和Last)、在指定位置插入元素(AddAfter()、AddBefore()、AddFirst()和AddLast()方法),刪除指定位置元素(Remove()、RemoveFirst()和RemoveLast()方法)、從鏈表的開頭(Find()方法)或結尾(FindLast()方法)開始搜索元素。
例子:
LinkedList<int> list = new LinkedList<int>(); list.AddFirst(2); list.AddFirst(1); list.AddLast(5); list.AddLast(6); list.AddAfter(list.Find(2),3); list.AddBefore(list.Find(5),4); foreach (var item in list) { Console.WriteLine(item); } list.RemoveLast(); Console.WriteLine("移除末尾元素後:"); foreach (var item in list) { Console.WriteLine(item); }
運行以上代碼,結果如下:
(六)有序列表
如果需要基於鍵對所需集合排序,就可以使用SortedList<TKey,TValue>類。這個類按照鍵給元素排序。
例子:
SortedList<string, string> list = new SortedList<string, string>(); list.Add("b", "lisi"); list.Add("a", "zhangsan"); list.Add("c","wangmazi"); foreach (var item in list) { Console.WriteLine("排序位置{0},是{1}",item.Key,item.Value); }
運行以上代碼,結果如下:
(七)字典
字典也成為映射或散射列表。字典的主要特性是能根據鍵快速查找值。也可以自由添加和刪除元素,這有點像List<T>類,但沒有在記憶體中移動後續元素的性能開銷。
1、鍵的類型
用作字典的鍵必須重寫Object類的GetHashCode()方法,並實現IEquatable<T>.Equals()方法,或重寫Object類的Equals()方法。也可以實現IEqualityComparer<T>介面的GetHashCode()方法和Equals()方法。
需要註意的是,如果A.Equals(B)方法返回true,則A.GetHashCode()和B.GetHashCode()方法必須總是返回相同的散列代碼。
字元串比Int32更適合用作鍵。
2、字典示例
Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("a", "zhang"); dic.Add("b", "li"); dic.Add("c", "wang"); foreach (var item in dic) { Console.WriteLine(item); }
3、Lookup類
Lookup<TKey,TElement>類非常類似於Dictionary<TKey,TValue>類,但把鍵映射到一個值集上。Lookup<TKey,TValue>類不能像一般的字典那樣創建,而必須調用ToLookup()方法,該方法返回一個Lookup<TKey,TElement>對象。調用ToLookup()方法需要傳遞一個Func<TSource,TKey>類型的委托來定義鍵的選擇器。
例子:
var personList = new List<Person>(); personList.Add(new Person() { Name = "zhangsan", Age = 13 }); personList.Add(new Person() { Name = "lisi", Age = 15 }); personList.Add(new Person() { Name = "wangmazi", Age = 13 }); personList.Add(new Person() { Name = "zhaoliu", Age = 18 }); var personLookup = personList.ToLookup(p => p.Age); foreach (var item in personLookup[13]) { Console.WriteLine(item.Name); }
4、有序字典
SortedDictionary<TKey,TValue>類是一個二叉搜索樹,其中的元素根據鍵來排序。該鍵類型必須實現IComparable<TKey>介面,在沒有實現的情況下,可以傳遞一個實現了IComparer<TKey>介面的比較器。
- SortedList<TKey,TValue>類使用的記憶體比SortedDictionary<TKey,TValue>類少。
- SortedDictionary<TKey,TValue>類的元素插入和刪除操作比較快。
- 在用已排好序的數據填充集合時,若不需要修改容量,SortedList<TKey,TValue>類就比較快。
(八)集
包含不重覆的集合成為“集(set)”。.NET Framework包含兩個集(HashSet<T>和SortedSet<T>),它們都實現ISet<T>介面。HashSet<T>集包含不重覆元素的無序列表,SortedSet<T>包含不重覆的有序列表。
例子:
1 var firstNameSet1 = new HashSet<string>(); 2 firstNameSet1.Add("zhang"); 3 firstNameSet1.Add("zhang"); 4 firstNameSet1.Add("li"); 5 firstNameSet1.Add("wang"); 6 firstNameSet1.Add("zhao"); 7 foreach (var item in firstNameSet1) 8 { 9 Console.WriteLine(item); 10 } 11 var firstNameSet2 = new HashSet<string>(); 12 firstNameSet2.Add("Smith"); 13 firstNameSet2.Add("Johnson"); 14 firstNameSet2.Add("Williams"); 15 firstNameSet2.Add("Jones"); 16 var firstNameSet = new SortedSet<string>(); 17 firstNameSet.UnionWith(firstNameSet1); 18 firstNameSet.UnionWith(firstNameSet2); 19 Console.WriteLine("將兩個無序集合併到有序集:"); 20 foreach (var item in firstNameSet) 21 { 22 Console.WriteLine(item); 23 }
運行以上代碼,結果如下:
(九)可觀察的集合
如果需要集合中的元素何時刪除或添加的信息,就可以使用ObservableCollection<T>類。
例子:
1 static void Main(string[] args) 2 { 3 ObservableCollection<string> obs = new ObservableCollection<string>(); 4 obs.CollectionChanged += Obs_changeInfo; 5 obs.Add("1"); 6 obs.Add("2"); 7 Console.ReadKey(); 8 } 9 10 11 private static void Obs_changeInfo(object sender, NotifyCollectionChangedEventArgs e) 12 { 13 Console.WriteLine("觸發事件操作方法:{0}",e.Action); 14 var targetElement = e.NewItems == null ? e.OldItems : e.NewItems; 15 foreach (var item in targetElement) 16 { 17 Console.WriteLine("觸發元素:{0}", item); 18 } 19 }
運行以上代碼,結果如下:
(十)位數組
如果需要處理的數字有許多位,就可以使用BitArray類和BitVector32結構。(完全不知道這個有什麼作用,暫不做筆記)
(十一)不變的集合
如果對象可以改變其狀態,就很難在多個同時運行的任務中使用。先填充集合,再將它變為不變的數組會更高效。需要進行一些處理時,可以再次使用可變的集合。此時可以使用不變集合提供的構建器類。
例子:
List<string> list = new List<string>(); list.Add("zhang"); list.Add("li"); var immutableList = list.ToImmutableList();//可變集合轉為不變集合 var immutableListBuilder = immutableList.ToBuilder();//重新轉換為可變集合 immutableListBuilder.Add("wang"); immutableList = immutableListBuilder.ToImmutable();//可變集合轉為不變集合 foreach (var item in immutableList) { Console.WriteLine(item); }
運行以上代碼,結果如下:
只讀集合提供集合的只讀試圖。在不使用只讀試圖訪問集合的情況下,該集合仍可修改。而不變集合無法修改。
(十二)併發集合
從.NET 4開始,.NET中名稱空間System.Collections.Concurrent中提供了幾個線程安全的集合類。為了對集合進行線程安全的訪問,定義了IProducerConsumerCollection<T>介面。這個介面中最重要的方法是TryAdd()方法和TryTake()方法。
併發集合參考:http://blog.csdn.net/wangzhiyu1980/article/details/45497907