程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#集合基礎與運用

C#集合基礎與運用

編輯:C#入門知識

1.集合接口與集合類型   (1)集合的命名空間   大多數集合類都可以在System.Collections和System.Collections.Generic名稱空間中找到。泛型集合位於System.Collections.Generic名稱空間中;專用於特定類型的集合類位於System.Collections.Specialized名稱空間中;線程安全的集合位於System.Collections.Concurrent名稱空間中。   (2)集合接口介紹   1、IEnumerable與IEnumerator接口   其實IEnumerable接口是非常的簡單,只包含一個抽象的方法GetEnumerator(),它返回一個可用於循環訪問集合的IEnumerator對象。       public interface IEnumerable       {           IEnumerator GetEnumerator();   }   IEnumerator對象有什麼呢?它是一個真正的集合訪問器,沒有它,就不能使用foreach語句遍歷集合或數組,因為只有IEnumerator對象才能訪問集合中的項。IEnumerator接口定義了:一個Current屬性用來獲取當前集合中的項;MoveNext方法將游標的內部位置向前移動;Reset方法將枚舉數設置為其初始位置,該位置位於集合中第一個元素之前。       public interface IEnumerator       {           object Current { get; }           bool MoveNext();           void Reset();   }   一個collection要支持foreach進行遍歷,就必須實現IEnumerable,並以某種方式返回迭代器對象:IEnumerator。   2、集合和列表實現的接口表   接口   說明   IEnumerable<T>   如果foreach語句用於集合,就需要此接口。   ICollection<T>   此集合定義了Count屬性、CopyTo、Add、Remove、Clear方法   IList<T>   可以通過位置訪問幾何元素   ISet<T>   此集合不允許有重復的元素   IDictionary<K,V>   含有鍵值對的集合   ILookup<K,V>   含有鍵值對的集合,但可以通過一個鍵包含多個值   IComparer<T>   集合元素比較器,用於集合元素的排序   IEqualityComparer<T>   用於字典集合的比較器   IProducerConsumerCollection<T>   線程安全的集合   2.集合的基本操作   (1)創建集合   使用默認的構造函數創建一個空集合,元素添加到集合之後,集合的容量就會擴大為4。當集合的容量被使用完,且還在向集合中添加元素時,集合的容量就會擴大成原來的2倍!可使用Capacity屬性設置或訪問集合的容量,使用Count屬性訪問集合的元素個數。也可使用TrimExcess方法調整集合容量,節省內存!       class Program       {           static void Main(string[] args)           {               List<int> list = new List<int>();//List<int> list = new List<int>(3)               for (int i = 0; i < 1025; i++)               {                   if (list.Count == (list.Capacity))                   {                       Console.WriteLine("容量使用量:"+list.Count + "/" + list.Capacity);                   }                   list.Add(i);               }               Console.WriteLine("容量使用量:" + list.Count + "/" + list.Capacity);               list.TrimExcess();//調整容量               Console.WriteLine("容量使用量:" + list.Count + "/" + list.Capacity);               Console.Read();           }   }   創建集合時可以為集合設置初始值,如下:   List<int> list = new List<int>() { 1,2,3,4,5,6,7,8,9,0};   List<string> list = new List<int>() { "aa", "bb", "cc" };   (2)添加元素   為集合添加元素可使用Add方法,還可以使用AddRange方法一次添加多個元素,因為AddRange方法的參數是IEnumerable<T>類型的對象,所以可以添加數組到集合裡。       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>();               list.AddRange(new string[]{"aa","bb","cc"});//添加數組               list.AddRange(list);//添加集合               foreach (string s in list)               {                   Console.WriteLine(s);               }               Console.Read();           }       }   (3)插入元素   插入元素可以使用Insert方法,同樣使用InsertRange方法插入多個元素,與AddRange方法類似。       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "aa", "bb", "ff" };               list.Insert(2, "cc");//插入元素               list.InsertRange(3, new string[] { "dd", "ee" });//插入集合               foreach (string s in list)               {                   Console.WriteLine(s);               }               Console.Read();           }       }   (4)訪問元素   可以使用索引器訪問集合中某個位置的元素,例如:       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "aa", "bb", "cc" };               Console.WriteLine(list[1]);//訪問第1個位置上的元素,下標從0開始               Console.Read();           }   }   集合的遍歷,除了使用foreach外,還可以使用集合的Foreach方法,該方法的參數是一個Action<T>委托類型,可以使用Lambda表達式。例如:       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "aa", "bb", "cc" };               list.ForEach(temp => Console.WriteLine("元素:" + temp));               //也可使用: list.ForEach(Console.WriteLine);               Console.Read();           }       }   (5)刪除元素   使用RemoveAt刪除指定位置的元素,使用Remove刪除指定的元素,使用RemoveRange刪除指定位置范圍的元素,使用Clear刪除所有元素,使用RemoveAll選擇刪除的元素。   注意:RemoveAll方法的參數是一個Predicate<T>委托類型,使用方式如下:       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "12", "123", "1234", "12345" };               //刪除長度小於4的元素               list.RemoveAll(x => { bool flag = x.Length < 4; return flag; });               list.ForEach(Console.WriteLine);               Console.Read();           }       }   (6)搜索元素   用於搜索的方法有:IndexOf、LastIndexOf、FindIndex、FindLastIndex、FindLast、Find、FindAll、Exists等方法。   IndexOf、LastIndexOf、FindIndex、FindLastIndex方法用於搜索元素的位置。   FindLast、Find、FindAll方法用於搜索滿足條件的元素。   Exists用於判斷集合是否存在某些元素。   參數可以使用Predicate<T>委托類型(Lambda表達式)的方法有:FindIndex、FindLastIndex、Find、FindLast、FindAll、Exists。例如:       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "12", "123", "1234", "12345" };               //搜索長度小於4的元素               list=list.FindAll(x => { bool flag = x.Length < 4; return flag; });               list.ForEach(Console.WriteLine);               Console.Read();           }       }   (7)元素排序   可以使用Sort方法對元素排序,也可以調用Reverse方法逆轉集合順序,Sort方法使用快速排序算法。Sort使用了幾個重載的方法,可以傳遞的參數有泛型委托Comparison<T>和泛型接口IComparer<T>,例如:       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "12", "123", "1234", "12345" };               //按字符串長度排序               list.Sort((x, y) => { return y.Length - x.Length; });               list.ForEach(Console.WriteLine);               Console.Read();           }       }   (8)類型轉換   使用ConvertAll<TOutput>方法可以把集合裡的所有元素轉換成另一種類型,ConvertAll<TOutput>使用了Converter委托,其定義如下:   public sealeddelegate TOutput Converter<TInput, TOutput>(TInput from)   TInput是委托方法的參數類型,TOutput是委托方法的返回值類型。例如:       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "12", "123", "1234", "12345" };               //把字符串轉換成數字(String->int)               List<int> array = list.ConvertAll<int>(temp => Int32.Parse(temp));               array.ForEach(temp => Console.WriteLine((temp + 1)));               Console.Read();           }       }   (9)只讀集合   集合的AsReadOnly方法可以返回一個ReadOnlyCollection<T>類型的集合;ReadOnlyCollection<T>是一個只讀集合類型,除了不能使用修改集合的方法與屬性,其它與集合一樣。   (10)集合常用的擴展方法(常用)   集合的擴展方法很多,這裡只舉兩個例子:Select與Where。例如:   Select:將序列中的每個元素投影到新表中。       class Program       {           static void Main(string[] args)           {               List<int> list = new List<int>() {1,3,5,7,9};               IEnumerable<string> array = list.Select<int, string>(x => (x * x).ToString());               foreach(string s in array)               {                   Console.WriteLine(s);               }               Console.Read();           }       }   Where:基於謂詞篩選值序列。       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string> { "1", "12", "123", "1234" };               //查詢長度小於3的元素               IEnumerable<string> query = list.Where(temp => temp.Length < 3);               foreach (string s in query)               {                   Console.WriteLine(s);               }               Console.Read();           }       }   3.常見集合的特性   (1)非泛型集合對應的泛型集合   非泛型集合類   對應的泛型集合類   ArrayList   List<T>   HashTable   DIctionary<T>   Queue   Queue<T>   Stack   Stack<T>   SortedList   SortedList<T>   (2)隊列(Queue<T>)   隊列是其元素以先進先出的方式來處理的集合。該集合沒有Add與Remove方法,其重要的方法如下:   Enqueue   在隊列的尾端添加元素   Dequeue   在隊列的頭部讀取並刪除元素   Peek   只讀取隊列頭部的元素   程序示例如:       class Program       {           static void Main(string[] args)           {               Queue<string> queue = new Queue<string>();               for (int i = 1; i < 5; i++)               {                   queue.Enqueue(i.ToString());//在尾部添加元素               }               PrintQueue(queue);//輸出元素               string s = queue.Dequeue();//讀取並刪除頭部元素               Console.WriteLine("讀取並刪除頭部元素:" + s);               queue.Enqueue("5");//在尾部添加元素               s = queue.Peek();//讀取頭部元素               Console.WriteLine("讀取頭部元素:" + s);               PrintQueue(queue);//輸出元素               Console.Read();           }           //輸出元素           private static void PrintQueue(Queue<string> q)           {               IEnumerable<string> list = q.Where(t => true);               foreach (string t in list)               {                   Console.WriteLine(t);               }           }       }   (3)棧(Stack<T>)   棧是一個後進先出的容器,其重要的方法如下:   Push   在棧頂壓入一個元素入棧   Pop   從站頂讀取並刪除一個元素   Peek   只從站頂讀取一個元素   程序示例如:       class Program       {           static void Main(string[] args)           {               Stack<string> stack = new Stack<string>();               for (int i = 1; i < 5; i++)               {                   stack.Push(i.ToString());//入棧               }               PrintStack(stack);//輸出元素               string s = stack.Pop();//讀取並刪除棧頂元素               Console.WriteLine("讀取並刪除棧頂元素:" + s);               s = stack.Peek();//只讀取棧頂元素               Console.WriteLine("只讀取棧頂元素:" + s);               PrintStack(stack);//輸出元素               Console.Read();           }           //輸出元素           private static void PrintStack(Stack<string> s)           {               IEnumerable<string> list = s.Where(t => true);               foreach (string t in list)               {                   Console.WriteLine(t);               }           }       }   (4)鏈表(LinkedList<T>)   LinkedList<T>是一個雙向鏈表。鏈表的優點是,如果將元素插入列表的中間位置,使用鏈表就會非常快,只需要修改下一個元素的Next引用與上一個元素的Previous引用。鏈表不能在集合中只存儲元素,必須要把元素存到LinkedListNode<T>類型的對象中,LinkedListNode<T>定義了屬性:List、Next、Value、Previous。List屬性返回與該節點相關的LinkedList<T>對象,Next、Previous用於遍歷鏈表。   LinkedList<T>對象可以訪問第一個和最後一個元素(Frist與Last)、在指定位置插入元素(AddAfter()、AddBefore()、AddFirst()、AddLast()方法),刪除指定位置的元素(ReMove()、ReMoveFirst()、RemoveLast()方法),從鏈表的開頭(Find())或結尾(FindLast())開始搜索元素。   程序示例如:       class Program       {           static void Main(string[] args)           {               LinkedList<int> link = new LinkedList<int>();               LinkedListNode<int> node;               for (int i = 0; i < 10; i++)               {                   node = new LinkedListNode<int>(i);                   if (i % 2 == 0)                   {                       link.AddFirst(node);//從頭部添加節點                   }                   else                   {                       link.AddLast(node);//從尾部添加節點                   }               }               PrintLink(link);//輸出元素               Console.Read();           }           //輸出元素           private static void PrintLink(LinkedList<int> l)           {               IEnumerable<int> list = l.Where(t => true);               foreach (int t in list)               {                   Console.WriteLine(t);               }           }       }   (5)有序列表(SortedList<K,V>)   SortedList<K,V>是基於鍵對集合進行排序的集合類,它只允許每個鍵只有一個對應值,如果需要每個鍵對應多個值可以使用Lookup<K,V>。可以使用foreach遍歷該集合,枚舉器返回的是KeyValuePair<K,V>類型的元素。除了使用Add方法添加元素,還可以使用索引器添加。例如:       class Program       {           static void Main(string[] args)           {               SortedList<string, string> sort = new SortedList<string, string>();               sort.Add("K1", "V1");//Add方法添加元素               sort["K2"] = "V2";//索引器添加元素               PrintSorted(sort);//輸出元素               Console.WriteLine("是否存在[K3]:" + sort.ContainsKey("K3"));               string value = null;               Console.WriteLine("是否存在[K2]:" + sort.TryGetValue("K2", out value));               Console.WriteLine("[K2]的值:" + value);               Console.Read();           }           //輸出元素           private static void PrintSorted(SortedList<string, string> s)           {               IEnumerable<KeyValuePair<string, string>> list = s.Where(t => true);               foreach (KeyValuePair<string, string> t in list)               {                   Console.WriteLine(t.Key + " ---> " + t.Value);               }           }       }   (6)字典   字典中鍵的類型必須重寫Object類的GetHashCode()方法。只要字典類需要確定元素的位置,他就會調用GetHashCode()方法。除了實現GetHashCode()方法外,鍵類型還必須實現IEquatable<T>.Equals()方法,或重寫Object類的Equals()方法。   因為不同的對象可能返回相同的散列碼(GetHashCode方法返回值),但是如果A.Equals(B)返回true,則A和B的散列碼就必須相同。這似乎有點奇怪,但這非常重要,因為字典的性能取決於GetHashCode()方法實現的代碼。   1、Dictionary<K,V>   Dictionary<K,V>類支持每個鍵關聯一個值,與SortedList<K,V>很類似。   2、Lookup<K,V>   Lookup<K,V>類把鍵映射到一個值集上。創建Lookup<K,V>類對象必須調用ToLookup()擴展方法,該方法返回一個Lookup<K,V>對象。ToLookup()方法需要一個Func<T,K>類型的委托參數,Func<T,K>類型定義了鍵的選擇器。   ToLookup()是一個奇妙的函數,用於對一個集合進行操作,創建一個1:n 的映射。 它可以方便的將數據分類成組,並生成一個字典供查詢使用。例如:       class Program       {           static void Main(string[] args)           {               List<string> list = new List<string>() { "1","12","123","1234","a","ab","abc"};               var lookup=list.ToLookup(x => x.Length);//根據元素的長度分組               foreach (var t in lookup)               {                   List<string> temp=t.ToList<string>();//把一組數據轉換成集合                   temp.ForEach(x=>Console.Write(x+"、"));//輸出集合                   Console.WriteLine();               }               Console.Read();           }       }   3、SortedDictionary<K,V>   SortedDictionary<K,V>類是一個二叉搜索樹,其中的元素根據鍵來排序,該鍵類型必須實現IComparable<T>接口。   SortedDictionary<K,V>與SortedList<K,V>的區別:   SortedList<K,V>類使用的內存比SortedDictionary<K,V>少。   SortedDictionary<K,V>類的元素的插入與刪除比較快。   在用於已排好序的集合,若不需要修改容量SortedList<K,V>會比較快。   區別的根本原因:SortedList<K,V>實現的是一個基於數組的集合,SortedDictionary<K,V>實現的是一個基於字典的集合。   (7)集(ISet<T>接口)   不包含重復元素的集合稱為集,.NET Framework包含兩個集(HashSet<T>和SortedSet<T>),它們都實現ISet<T>接口。HashSet<T>是不包含重復元素的無序列表,SortedSet<T>是不包含重復元素的有序列表。   4.可觀察的集合(深入)   (1)ObservableCollection<T>類簡介   ObservableCollection<T>類是為WPF定義的,這樣UI就可以得知集合的變化,因為只要修改了ObservableCollection<T>類對象集合中的元素,它就會產生CollectionChanged 事件。   (2)使用示例       class Program       {           static void Main(string[] args)           {               ObservableCollection<int> list = new ObservableCollection<int>();               list.CollectionChanged += ListCollectionChanged;//添加事件方法               list.Add(10);//產生事件               list.Add(20);//產生事件               list.Remove(10);//產生事件               Console.Read();           }           //事件方法           private static void ListCollectionChanged(object sender,   NotifyCollectionChangedEventArgs e)           {               Console.WriteLine("本次修改的方式:" + e.Action.ToString());               if (e.OldItems != null)               {                   Console.WriteLine("本次修改的位置:" + e.OldStartingIndex);                   Console.WriteLine("本次修改的元素個數:" + e.OldItems.Count);               }               if (e.NewItems != null)               {                   Console.WriteLine("本次修改的位置:" + e.NewStartingIndex);                   Console.WriteLine("本次修改的元素個數:" + e.NewItems.Count);               }               Console.WriteLine();           }       }   5.位數組(深入)   (1)BitArray、BitVector32介紹   如果需要處理的數字有許多位,就可以使用BitArray類與BitVector32結構。它們的區別是:BitArray類可以重新設置大小,它可以包含很多位;BitVector32結構是基於棧的,因此比較快,但它只能包含32為,它們存在一個整數中。   (2)BitArray   BitArray類是一個引用類型,它包含一個int數組,其中32位使用一個新整數,其成員如下:   Count、Length   Count、Length可得到數組的位數,Length可設置其數組的大小   Get、Set   使用Get、Set可訪問數組中的位   SetAll   SetAll()方法設置所有的位值   Not   Not()方法對數組中所有的位求反   And、Or、Xor   And()是與操作,Or()是或操作,Xor()是異或操作   程序示例:       class Program       {           static void Main(string[] args)           {               BitArray barray = new BitArray(20);               barray.SetAll(true);//對所有位賦值               PrintBitArray(barray);//輸出               barray.Set(1, false);               barray[2] = false;               PrintBitArray(barray);//輸出               Console.Read();           }           //輸出函數           private static void PrintBitArray(BitArray b)           {               foreach (bool bit in b)               {                   Console.Write(bit ? 1 : 0);               }               Console.WriteLine();           }       }   (3)BitVector32   BitVector32結構的效率更高,因為它是值類型!它常用成員如下:   Data   Data屬性把BitVector32結構返回成一個整數   索引器   訪問BitVector32結構的值可以使用索引器   CreateMask   這是一個靜態方法,為訪問BitVector32結構中特定的類創建掩碼   CreateSection   這是一個靜態方法,用於創建32位中的幾個片段   程序示例:       class Program       {           static void Main(string[] args)           {               BitVector32 b32 = new BitVector32();               PrintBitVector32(b32);//輸出位               int bit = BitVector32.CreateMask();               for (int i = 0; i < 4; i++)               {                   b32[bit] = true;                   Console.WriteLine(bit);                   PrintBitVector32(b32);//輸出位                   b32[bit] = false;                   bit = BitVector32.CreateMask(bit);               }               Console.WriteLine(b32.Data);//輸出數               Console.Read();           }           //輸出函數           private static void PrintBitVector32(BitVector32 b32)           {               for (int i = 0; i < 32; i++)               {                   Console.Write(b32[i] ? 1 : 0);               }               Console.WriteLine();           }       }   6.並發集合(.NET 4新增)   (1)ConcurrentQueue<T>   這個集合類用一種免鎖定的算法實現,訪問隊列元素的方法有:TryDequeue、TryPeek和Enqueue。   (2)ConcurrentStack<T>   這個集合類定義了:Push()、PushRange、TryPeek、TryPop、TryPopRange方法。   (3)ConcurrentBag<T>   ConcurrentBag<T>表示對象的線程安全的無序集合。對於同一個線程值的添加和刪除是非常快的,因為ConcurrentBag內部將數據按線程的標識而獨立存儲,所以一個線程從自己的數據中移除一個數據是非常快的,當然如果這個線程中沒有數據,那麼只能從其他線程中移除數據,此時會發生一些性能損耗從而確保線程安全!   (4)ConcurrentDictionary<K, V>   這是一個線程安全的鍵值集合,TyrAdd、TryGetValue、TryRemove、TryUpdate方法以非阻塞的方式訪問元素。   (5)BlockingCollection<T>   這個集合在可以添加或提取元素元素之前,會阻塞線程並一直等待。可以使用Add、Take方法用來添加和刪除元素,這些方法會阻塞當前線程,一直等到任務可以執行為止。   7.不同集合類的性能

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved