看完了以家人之名後,大叔該專心回來分享c#教學了,大叔的工作寫C#程式也有四年多了,以前寫PHP時那種結合陣列(associative array)寫的很爽,現在用C#來工作,那種向量陣列(vector array)(C、C++、Java、C#…),事先就得宣告陣列大小,讓我有點不適應,你想想如果我要做一個以家人之名的演員陣列,那是不是我要先看完所有40集的電視後才能確定陣列的大小。
而在PHP中,我可以這樣寫,看到哪寫到哪:
$actors = array(); $actors['李尖尖'] = '譚松韻'; $actors['凌霄'] = '宋威龍'; $actors['賀子秋'] = '張新成'; print_r($actors);
在C# 裡其實也有類似PHP的結合陣列用法,就是使用List內建泛型類別,這有點像是不用宣告長度的陣列(Array),是沒有PHP那樣的直覺,需要稍微記一下 list這個單字,怕忘記可以將這篇c# 教學文章加到我的最愛或是書籤中喔,以後有需要再點進來看。
什麼是 C# List?
命名空間:System.Collections.Generic
組件:mscorlib.dll, System.Collections.dll
表示可以依照索引存取的強類型物件列表。 提供搜尋、排序和管理清單的方法。
宣告:
//範例1: List<T> mList = new List<T>(); //T爲列表中元素類型,現在以string類型作爲例子: List<string> mList = new List<string>(); //範例2: List<T> testList =new List<T> (IEnumerable<T> collection); //以一個集合作爲參數創建List: string[] temArr = { "李尖尖", "凌霄", "賀子秋", "李海潮", "凌和平", "齊明月", "唐燦", "杜鵑"}; List<string> testList = new List<string>(temArr);
List<T>裡的’T’是什麼?
List<T>是.NET Framework類別庫提供的泛型集合,將<>號裡面的T改成我們指定的型別,就會產生對應型別的集合,存入取出的過程都會是我們指定的型別,而不用每次都轉換成object影響到效能,編譯器也會知道我們指定成什麼型別,幫我們正確的進行型別檢查,免得執行時才發現選錯型別。
常用的屬性和方法
屬性 |
說明 |
Capacity |
在不需要調整大小之下,取得或設定內部資料結構可以保存的項目總數。 |
Count |
取得 List中包含的元素數目 |
Item |
取得或設定索引中的項目 |
方法 | 說明 |
Add | 將物件加入至 List的最後面 |
AddRange | 將特定集合的元素加入至 List的最後面 |
BinarySearch | 使用預設的比較子並傳回元素以零為起始的索引,來搜尋元素之整個排序的 List |
Clear |
將所有元素從 List中移除 |
Contains | 判斷元素是否在 List中 |
Equals(Object) | 判斷指定的物件是否等於目前的物件。 |
Find | 擷取符合指定的元素,並傳回整個List中第一個相符的元素 |
Foreach | 在 List 的每一個元素上執行指定之動作。 |
IndexOf(T) | 搜尋指定的物件,並傳回整個 List 中第一個相符合元素的索引 |
Insert(Int32, T) | 將元素插入至 List 中指定的索引位置 |
InsertRange(Int32, IEnumerable<T>) | 將集合的元素插入位於指定索引的 List 中 |
Remove(T) | 從 List 移除特定物件的第一個相符合元素 |
RemoveAt(Int32) | 移除 List中指定索引的元素 |
RemoveRange(Int32, Int32) | 從 List 移除的元素範圍。 |
Sort | 使用預設比較子來排序整個 List 中的元素 |
TrimExcess | 將容量設為 List 中元素的實際數目,如果該數目小於臨界值。 |
TrueForAll | 判斷 List 中的每一個元素是否符合指定之述詞所定義的條件。 |
C# List的Add與AddRange方法
(1)Add:添加單個元素
List<string> Soundtracks1= new List<string>(); Soundtracks1.Add("無畏"); Soundtracks1.Add("我會守在這裡"); Soundtracks1.Add("看不見的光"); Soundtracks1.Add("Like A Breeze"); Soundtracks1.Add("雨");
再看一個c# list add new範例
using System; using System.Collections.Generic; // Simple business object. A PartId is used to identify the type of part // but the part name can change. public class Part : IEquatable<Part> { public string PartName { get; set; } public int PartId { get; set; } public override string ToString() { return "ID: " + PartId + " Name: " + PartName; } public override bool Equals(object obj) { if (obj == null) return false; Part objAsPart = obj as Part; if (objAsPart == null) return false; else return Equals(objAsPart); } public override int GetHashCode() { return PartId; } public bool Equals(Part other) { if (other == null) return false; return (this.PartId.Equals(other.PartId)); } // Should also override == and != operators. } public class Example { public static void Main() { // Create a list of parts. List<Part> parts = new List<Part>(); // Add parts to the list. parts.Add(new Part() { PartName = "crank arm", PartId = 1234 }); parts.Add(new Part() { PartName = "chain ring", PartId = 1334 }); parts.Add(new Part() { PartName = "regular seat", PartId = 1434 }); parts.Add(new Part() { PartName = "banana seat", PartId = 1444 }); parts.Add(new Part() { PartName = "cassette", PartId = 1534 }); parts.Add(new Part() { PartName = "shift lever", PartId = 1634 }); // Write out the parts in the list. This will call the overridden ToString method // in the Part class. Console.WriteLine(); foreach (Part aPart in parts) { Console.WriteLine(aPart); } // Check the list for part #1734. This calls the IEquatable.Equals method // of the Part class, which checks the PartId for equality. Console.WriteLine("nContains("1734"): {0}", parts.Contains(new Part { PartId = 1734, PartName = "" })); // Insert a new item at position 2. Console.WriteLine("nInsert(2, "1834")"); parts.Insert(2, new Part() { PartName = "brake lever", PartId = 1834 }); //Console.WriteLine(); foreach (Part aPart in parts) { Console.WriteLine(aPart); } Console.WriteLine("nParts[3]: {0}", parts[3]); Console.WriteLine("nRemove("1534")"); // This will remove part 1534 even though the PartName is different, // because the Equals method only checks PartId for equality. parts.Remove(new Part() { PartId = 1534, PartName = "cogs" }); Console.WriteLine(); foreach (Part aPart in parts) { Console.WriteLine(aPart); } Console.WriteLine("nRemoveAt(3)"); // This will remove the part at index 3. parts.RemoveAt(3); Console.WriteLine(); foreach (Part aPart in parts) { Console.WriteLine(aPart); } /* ID: 1234 Name: crank arm ID: 1334 Name: chain ring ID: 1434 Name: regular seat ID: 1444 Name: banana seat ID: 1534 Name: cassette ID: 1634 Name: shift lever Contains("1734"): False Insert(2, "1834") ID: 1234 Name: crank arm ID: 1334 Name: chain ring ID: 1834 Name: brake lever ID: 1434 Name: regular seat ID: 1444 Name: banana seat ID: 1534 Name: cassette ID: 1634 Name: shift lever Parts[3]: ID: 1434 Name: regular seat Remove("1534") ID: 1234 Name: crank arm ID: 1334 Name: chain ring ID: 1834 Name: brake lever ID: 1434 Name: regular seat ID: 1444 Name: banana seat ID: 1634 Name: shift lever RemoveAt(3) ID: 1234 Name: crank arm ID: 1334 Name: chain ring ID: 1834 Name: brake lever ID: 1444 Name: banana seat ID: 1634 Name: shift lever */ } }
(2)AddRange:添加實作了界面IEnumerable<T>的一個泛型集合的所有元素到指定泛型集合末尾
string[] input = { "無畏", "我會守在這裡", "看不見的光" }; List<string> Soundtracks2 = new List<string>(input); Soundtracks2.AddRange(dinosaurs);
※2022/07/28
今天分享一個c# list add list的範例,中文白話的意思就是使用 C# 中的 List.AddRange() 函式將列表新增到另一個列表
以下程式碼範例展示如何使用 C# 中的 List.AddRange() 函式將一個列表新增到另一個列表。
using System; using System.Collections.Generic; namespace add_list { static void Main(string[] args) { List<string> first = new List<string> { "do", "rey", "me" }; List<string> second = new List<string> { "fa", "so", "la", "te" }; first.AddRange(second); foreach(var e in first) { Console.WriteLine(e); } } } }
輸出:
do rey me fa so la te
用foreach 取出List 裡的值
// 可用foreach 取出List 裡的值 foreach(string myStringList in Soundtracks1) { Console.WriteLine(myStringList); }
程式輸出如圖:
// 取出單一個List 裡的值,如同陣列(Array)用法 // 無畏 Soundtracks2[0]; // 無畏 Soundtracks1[0]; 下面的程式碼可以顯示List中第三個元素值 Console.WriteLine(Soundtracks1[2]);
如何使用 C# List 屬性
List 的 Capacity 代表集合的容量,Count 代表集合中的數量
隨著項目新增至 List 物件中,會重新配置內部陣列來增加容量。
重新配置的意義:
當加入新項目至 List 物件中時會去檢查 List 物件的 Capacity 與 Count 屬性值
當 Count 等於 Capacity,會自動重新配置內部陣列,並將新陣列的容量設為 Capacity 的倍數,並且在加入新項目以前,複製現有項目至新陣列,接著再將新項目加入。
成本:
1.建立一個新的內部陣列
2.將現有項目複製到新的內部陣列中
當 List 物件中的項目多且項目資料量大時,重新配置的成本不小。
using System; using System.Collections.Generic; namespace ConsoleApp1 { class Program { static void Main(string[] args) { List<string> Soundtracks1 = new List<string>(); Soundtracks1.Add("無畏"); Soundtracks1.Add("我會守在這裡"); Soundtracks1.Add("看不見的光"); Soundtracks1.Add("Like A Breeze"); Soundtracks1.Add("雨"); output(Soundtracks1); Soundtracks1.Add("If Rain"); output(Soundtracks1); Soundtracks1.AddRange(new string[] {"My Everything","金鼎巷","杏林湾商务运营中心","莲花新城公交站947路" }); output(Soundtracks1); Soundtracks1.AddRange(new string[] { "李尖尖", "凌霄", "賀子秋", "李海潮" }); output(Soundtracks1); Console.ReadLine(); //List count = 5, capacity = 8 //List count = 6, capacity = 8 //List count = 10, capacity = 16 //List count = 14, capacity = 16 } static void output(List<string> l) { Console.WriteLine("List count={0}, capacity={1}", l.Count, l.Capacity); } } }
所以一般建議若項目數量是可預測的話,在建立 List<T> 物件時就設定 Capacity 大小,看到capacity的配置後,想要寫爽變動陣列,還是要考慮一下程式效能。
List<string> testList = new List<string>(32)
當 List<T> 物件項目加入完成後可使用 TrimExcess() 方法,或設定 Capacity = Count 來減少不必要的記憶體空間,不過這些舉動也會引發重新配置。
但使用TrimExcess() 方法時會去檢查項目大於容量的 90%,就不會執行重新配置,避免為取得一點利益而產生昂貴的重新配置成本。
myList.TrimExcess(); //視情況重新配置
myList.Capacity = myList.Count;
C#中使用List集合的Insert方法在指定位置插入元素
在C#的List集合等資料型別變數中,我們可以使用c# list insert方法在指定的索引位置插入一個新元素,例如指定在List集合的第一個位置寫入一個新元素或者在List集合的中間某個位置插入一個新元素。List集合類的Insert方法的格式為ListObj.Insert(index,listNewObject),其中ListObj代表List集合物件,index代表要插入元素的位置,listNewObject表示插入值。
例如我們有個string型別的List集合actorsList,我們需要在actorsList集合的第一個位置插入”谭松韵”,則可以使用下列語法來實現:
actorsList.Insert(0,”谭松韵”);
InsertRange(int index,IEnumerable<T> items) 在index下標處插入一組元素,該下標以及之後的元素依次後移
下面的程式碼在第3個位置插入一個字串,在第2個位置插入一個集合
testList.Insert(3, "塗松岩"); // Collection of new authors string[] newAuthors = { "張晞臨", "孫銥", "何瑞賢" }; // Insert array at position 2 testList.InsertRange(2, newAuthors);
C# 從集合中刪除元素
1.C# 使用 Remove() 方法從 List 中刪除元素
這個 Remove() 方法根據集合上的名稱刪除元素。此方法的語法如下:
ListName.Remove(“NameOfItemInList”);
範例:
using System; using System.Collections.Generic; namespace ConsoleApp1 { class Program { static void Main(string[] args) { List<string> Soundtracks1 = new List<string>(); Soundtracks1.Add("無畏"); Soundtracks1.Add("我會守在這裡"); Soundtracks1.Add("看不見的光"); Soundtracks1.Add("Like A Breeze"); Soundtracks1.Add("雨"); output(Soundtracks1); Soundtracks1.Add("If Rain"); output(Soundtracks1); Soundtracks1.AddRange(new string[] {"My Everything","金鼎巷","杏林湾商务运营中心","莲花新城公交站947路" }); output(Soundtracks1); Soundtracks1.AddRange(new string[] { "李尖尖", "凌霄", "賀子秋", "李海潮" }); output(Soundtracks1); string[] temArr = { "李尖尖", "凌霄", "賀子秋", "李海潮", "凌和平", "齊明月", "唐燦", "杜鵑" }; List<string> testList = new List<string>(temArr); testList.Insert(3, "塗松岩"); // Collection of new authors string[] newAuthors = { "張晞臨", "孫銥", "何瑞賢" }; // Insert array at position 2 testList.InsertRange(2, newAuthors); Console.WriteLine("刪除前集合:"); foreach (string myStringList in testList) { Console.WriteLine(myStringList); } Console.WriteLine(); //Use of Remove() method testList.Remove("孫銥"); Console.WriteLine("刪除後集合:"); foreach (string myStringList in testList) { Console.WriteLine(myStringList); } Console.ReadLine(); //List count = 5, capacity = 8 //List count = 6, capacity = 8 //List count = 10, capacity = 16 //List count = 14, capacity = 16 } static void output(List<string> l) { Console.WriteLine("List count={0}, capacity={1}", l.Count, l.Capacity); } } }
2.C# 使用 RemoveAt() 方法從 List 中刪除元素
RemoveAt() 方法根據該元素的索引位置從 List 中刪除該元素。要知道 C# 中的索引以 0 開頭。因此,選擇索引位置時要小心。此方法的語法如下:
ListName.RemoveAt(Index);
範例:
using System; using System.Collections.Generic; namespace ConsoleApp1 { class Program { static void Main(string[] args) { List<string> Soundtracks1 = new List<string>(); Soundtracks1.Add("無畏"); Soundtracks1.Add("我會守在這裡"); Soundtracks1.Add("看不見的光"); Soundtracks1.Add("Like A Breeze"); Soundtracks1.Add("雨"); output(Soundtracks1); Soundtracks1.Add("If Rain"); output(Soundtracks1); Soundtracks1.AddRange(new string[] {"My Everything","金鼎巷","杏林湾商务运营中心","莲花新城公交站947路" }); output(Soundtracks1); Soundtracks1.AddRange(new string[] { "李尖尖", "凌霄", "賀子秋", "李海潮" }); output(Soundtracks1); string[] temArr = { "李尖尖", "凌霄", "賀子秋", "李海潮", "凌和平", "齊明月", "唐燦", "杜鵑" }; List<string> testList = new List<string>(temArr); testList.Insert(3, "塗松岩"); // Collection of new authors string[] newAuthors = { "張晞臨", "孫銥", "何瑞賢" }; // Insert array at position 2 testList.InsertRange(2, newAuthors); Console.WriteLine("刪除前集合:"); foreach (string myStringList in testList) { Console.WriteLine(myStringList); } Console.WriteLine(); //Use of RemoveAt() method testList.RemoveAt(3); Console.WriteLine("刪除後集合:"); foreach (string myStringList in testList) { Console.WriteLine(myStringList); } Console.ReadLine(); //List count = 5, capacity = 8 //List count = 6, capacity = 8 //List count = 10, capacity = 16 //List count = 14, capacity = 16 } static void output(List<string> l) { Console.WriteLine("List count={0}, capacity={1}", l.Count, l.Capacity); } } }
3.C# 使用 RemoveRange() 方法從 List 中刪除元素
在 C# 中,我們也可以同時刪除多個元素。為此,可以使用 RemoveRange() 方法。將要刪除的元素範圍作為引數傳遞給該方法。此方法的語法如下:
ListName.RemoveRange(int index, int count);
index 是要刪除的元素的起始索引,count 是要刪除的元素的數量。
範例:
using System; using System.Collections.Generic; namespace ConsoleApp1 { class Program { static void Main(string[] args) { List<string> Soundtracks1 = new List<string>(); Soundtracks1.Add("無畏"); Soundtracks1.Add("我會守在這裡"); Soundtracks1.Add("看不見的光"); Soundtracks1.Add("Like A Breeze"); Soundtracks1.Add("雨"); output(Soundtracks1); Soundtracks1.Add("If Rain"); output(Soundtracks1); Soundtracks1.AddRange(new string[] {"My Everything","金鼎巷","杏林湾商务运营中心","莲花新城公交站947路" }); output(Soundtracks1); Soundtracks1.AddRange(new string[] { "李尖尖", "凌霄", "賀子秋", "李海潮" }); output(Soundtracks1); string[] temArr = { "李尖尖", "凌霄", "賀子秋", "李海潮", "凌和平", "齊明月", "唐燦", "杜鵑" }; List<string> testList = new List<string>(temArr); testList.Insert(3, "塗松岩"); // Collection of new authors string[] newAuthors = { "張晞臨", "孫銥", "何瑞賢" }; // Insert array at position 2 testList.InsertRange(2, newAuthors); Console.WriteLine("刪除前集合:"); foreach (string myStringList in testList) { Console.WriteLine(myStringList); } Console.WriteLine(); //Use of RemoveRange() method testList.RemoveRange(3, 2); Console.WriteLine("刪除後集合:"); foreach (string myStringList in testList) { Console.WriteLine(myStringList); } Console.ReadLine(); //List count = 5, capacity = 8 //List count = 6, capacity = 8 //List count = 10, capacity = 16 //List count = 14, capacity = 16 } static void output(List<string> l) { Console.WriteLine("List count={0}, capacity={1}", l.Count, l.Capacity); } } }
4.C#中List集合使用Clear方法清空集合
在C#中的List集合操作過程中,有時候需要清空List集合中的元素,將之重置為一個初始化的List集合,此時就可以使用到List集合的擴展方法Clear()方法,此方法將清空List集合中所有的元素,清空後List集合中的元素個數為0。
例如有個List<string>的集合list1,內部存儲7個字串,清空list1中的元素可使用下列語句:
List<string> list1 = new List<string>() { “李尖尖總是「善待這世界的尖銳」”, “譚松韻:「我很幸運,用童年治癒著自己的一生」”, “「李尖尖的人生哲學」”, “凌霄的成長,是選擇原諒”, “凌霄:「如果覺得做錯了,只有活著才能夠彌補」”, “賀子秋與童年和解,獲得媽媽的疼愛”, “家是永遠的避風港” };
list1.Clear();
C# List如何尋找元素?
有兩種方法:
1.使用IndexOf判斷元素第一次出現的索引位置
在C#的List集合操作中,有時候需要判斷元素在List集合中第一次出現的索引位置資訊,此時需要使用到List集合的IndexOf方法來判斷,如果元素存在List集合中,則IndexOf方法傳回所在的索引位置資訊,如果不存在則返回-1,IndexOf方法為int IndexOf(T item),item代表需要判斷的元素。
例如有個List<int>的集合list2,需要判斷數字17在list1集合中第一次出現的索引位置資訊:
List<int> list2 = new List<int>() { 5, 7, 3, 10,17, 15, 18, 20, 13, 2,12 };
var index= list2.IndexOf(17);
計算結果為,index=4。
2.使用contains()方法,判斷元素是否包含特定值
語法:public bool Contains (T item);
範例:list2.Contains(17);
IndexOf 跟 contains在效能上的比較有滿多討論的,一般都說是IndexOf較好,測試範例如下:
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); Random r = new Random(); int value =r.Next(0, 100000000); //自己去變 for (int i = 0; i < 10; i++) { Console.WriteLine("=========="); Console.WriteLine("value=" + value); stopwatch.Start(); bool IsContainValue = (list.IndexOf(value) != -1); stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed); stopwatch.Reset(); stopwatch.Start(); list.Contains(value); stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed); stopwatch.Reset(); //Console.WriteLine("=========="); value = r.Next(0, 100000000); //自己去變 }
但ITREAD上有篇《List集合的contains() ,indexOf的比較》卻提到是『contains()效率比較高』,卻沒有範例佐證,是有點詭異的說法。
C# List 如何排序?
List<T>作為集合,排序也是它的一個基本功能。List<T>可以通過Sort()對集合中的元素進行從小到大排序,同時Sort()還接收自定義比較器,這樣開發人員可以根據需要指定希望的比較方式。Sort()方法的4個版本的定義如下:
- Sort() 使用預設的比較子來排序在整個 List<T> 中的元素。
- Sort(IComparer<T>) 使用指定的比較子來排序在整個 List<T> 中的元素
- Sort(Int32, Int32, IComparer<T>) 使用指定的比較子對 List<T> 中某段範圍內的元素進行排序。
- Sort(Comparison<T>) 使用指定的 Comparison<T> 來排序在整個 List<T> 中的元素。
方法一、Sort()
該方法為系統預設的方法,單一參數時會預設進行升序排序。
List<int> list1 = new List<int>(); int[] animals = { 989, 515, 298,112,581 }; list1.AddRange(animals); list1.Sort(); foreach (int myintList in list1) { Console.WriteLine(myintList); } List<string> list2 = new List<string>(); list2.Add("譚松韻"); list2.Add("宋威龍"); list2.Add("張新成"); list2.Add("塗松岩"); list2.Add("張晞臨"); list2.Sort(); foreach (string myintList in list2) { Console.WriteLine(myintList); }
如果遇到多參數(Name、Age)排序時,需要對該預設方法進行修改。
如果沒有修改這個方法,會產生未處理的例外狀況
System.InvalidOperationException: ‘無法比較陣列中的兩個元素。’
ArgumentException: 至少一個物件必須實作 IComparable。
A:People類別繼承IComparable介面,實作CompareTo()方法
IComparable<T>:定義由值型別或類別實作的通用比較方法,為了在建立特定於型別的比較方法以對元素進行排序。
原理:自行實作的CompareTo()方法會在list.Sort()內部進行元素兩兩比較,最後實作排序
public class People : IComparable<People> { public int Age { get; set; } public string Name { get; set; } public People(string name, int age) { this.Name = name; this.Age = age; } public override string ToString() { string result = ""; result = "[" + this.Name + "," + this.Age.ToString() + "]"; return result; } // list.Sort()時會根據該CompareTo()進行自定義比較 public int CompareTo(People other) { int x = this.Name.CompareTo(other.Name); if (x == 0) { if (this.Age > other.Age) x = 1; else if (this.Age == other.Age) x = 0; else x = -1; } return x; } } List<People> peopleList = new List<People>(); peopleList.Add(new People("譚松韻", 31)); peopleList.Add(new People("譚松韻", 22)); peopleList.Add(new People("宋威龍", 22)); peopleList.Add(new People("張新成", 26)); peopleList.Add(new People("塗松岩", 45)); peopleList.Add(new People("張晞臨", 55)); peopleList.Add(new People("張晞臨", 65)); peopleList.Sort(); foreach (People myintList in peopleList) { Console.WriteLine(myintList.Name+","+ myintList.Age); } Console.ReadLine();
方法二、Sort(IComparer<T>)
使用指定的比較子來排序在整個 List<T> 中的元素
跟上述繼承IComparable的方法不同,這個方法不可在People內繼承實作IComparer介面,而是需要新建比較方法類別進行介面實作
B.新建PeopleComparer類別、繼承IComparer介面、實作Compare()方法
原理:list.Sort()將PeopleComparer類別的元素作為引數,在內部使用Compare()方法進行兩兩比較,最終實作排序(注意:上述方法為CompareTo(),此處為Compare()方法)
// 自定義比較方法類別 class PeopleComparer : IComparer<People> { // 不同於CompareTo()單引數,此處為雙引數 public int Compare(People x, People y) { if (x.Name != y.Name) { return x.Name.CompareTo(y.Name); } else if (x.Age != y.Age) { return x.Age.CompareTo(y.Age); } else return 0; } } // 客戶端 // 傳入引數為自定義比較類別的元素 peopleList.Sort(new PeopleComparer()); foreach (People myintList in peopleList) { Console.WriteLine(myintList.Name + "," + myintList.Age); } Console.ReadLine();
方法三、Sort(Int32, Int32, IComparer<T>)
使用指定的比較子對 List<T> 中某段範圍內的元素進行排序。
原理:List<T>.Sort(int index,, int count, IComparer<T> Comparer) 方法的引數:待排元素起始索引、待排元素個數、排序方法
// 客戶端 // 傳入引數為自定義比較類別的元素 peopleList.Sort(2,3,new PeopleComparer()); foreach (People myintList in peopleList) { Console.WriteLine(myintList.Name + "," + myintList.Age); } Console.ReadLine();
方法四、Sort(Comparison<T>)
使用指定的 Comparison<T> 來排序在整個 List<T> 中的元素。
不同於上述繼承介面的方法,此方法的引數為 泛型委派 Comparison<T>
委派原型:public delegate int Comparison<in T>(T x,T y);
C:依照委派的使用方法,首先建立委派執行個體MyComparison,並繫結到自定義的比較方法PeopleComparison()上,最終呼叫list.Sort()時 將委派執行個體傳入
原理:list.Sort()根據傳入的委派方法,進行兩兩元素比較最後實作排序
public static int PeopleComparison(People p1, People p2) { if (p1.Name != p2.Name) { return p1.Name.CompareTo(p2.Name); } else if (p1.Age != p2.Age) { return p1.Age.CompareTo(p2.Age); } else return 0; } static void Main(string[] args) { List<People> peopleList = new List<People>(); peopleList.Add(new People("譚松韻", 31)); peopleList.Add(new People("譚松韻", 22)); peopleList.Add(new People("宋威龍", 22)); peopleList.Add(new People("張新成", 26)); peopleList.Add(new People("塗松岩", 45)); peopleList.Add(new People("張晞臨", 55)); peopleList.Add(new People("張晞臨", 65)); //peopleList.Sort(); // 客戶端 // 傳入引數為自定義比較類別的執行個體 //peopleList.Sort(2,3,new PeopleComparer()); //foreach (People myintList in peopleList) //{ // Console.WriteLine(myintList.Name + "," + myintList.Age); //} //Console.ReadLine(); // 方法0 建立委派執行個體並繫結 Comparison<People> MyComparison = PeopleComparison; // 傳入該執行個體實作比較方法 peopleList.Sort(MyComparison); foreach (People myintList in peopleList) { Console.WriteLine(myintList.Name + "," + myintList.Age); } Console.ReadLine(); }
此外,既然Comparison<T>是泛型委派,則完全可以用 Lambda表示式進行描述
// Lambda表示式實現Comparison委託 peopleList.Sort((p1, p2) => { if (p1.Age != p2.Age) { return p2.Age.CompareTo(p1.Age); } else if (p1.Name != p2.Name) { return p2.Name.CompareTo(p1.Name); } else return 0; }); foreach (People myintList in peopleList) { Console.WriteLine(myintList.Name + "," + myintList.Age); } Console.ReadLine();
如何反轉C# List的元素?
在C#的List集合操作中,有時候需要對List集合中的元素的順序進行倒序反轉操作,此時就可使用到List集合中的Reverse方法來實現此功能,Reverse方法的簽名爲void Reverse(),此方法不需要任何參數,呼叫void Reverse()方法可將整個List集合中的元素的順序反轉過來。
A.Reverse()
反轉整個 List<T> 中項目的順序。
例如有個List集合list1中含有元素1至10,需要將這個list1集合中的元素反轉爲10至1的倒序順序排列可使用下列語句:
List<int> list1 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
list1.Reverse();
B.Reverse(Int32, Int32)
反向指定範圍中項目的順序。
public void Reverse (int index, int count);
參數
index Int32 要反向範圍內之以零為起始的起始索引。
count Int32 要反向範圍中的項目數。
例外狀況
ArgumentOutOfRangeException
index 小於 0。
-或- count 小於 0。
ArgumentException
index 和 count 不代表 List<T> 中項目的有效範圍。
如何搜尋 C# List 的元素?
List<T>的BinarySearch方法搜尋一個排序 List中的元素並傳回以零為起始的索引項目
多載
A.BinarySearch(T):使用預設的比較子並傳回項目以零為起始的索引,來搜尋項目之整個排序的 List<T>。
B.BinarySearch(T, IComparer<T>):使用指定的比較子並傳回項目以零為起始的索引,來搜尋項目之整個排序的 List<T>。
C.BinarySearch(Int32, Int32, T, IComparer<T>):使用指定的比較子在已經過排序之 List<T> 內,搜尋某範圍的項目,並傳回該項目以零為起始的索引。
A.BinarySearch(T)方法
用法:public int BinarySearch (T item);
參數:item T 要尋找的物件。 參考類型的值可以是 null。
傳回:Int32
如果有找到 item,則為已排序的 List<T> 中 item 之以零為起始的索引,否則便為負數,此負數為大於 item 的下一個項目索引之位元補數,或者,如果沒有更大的項目,則為 Count 的位元補數。
例外狀況:InvalidOperationException
預設比較子 Default 找不到 IComparable<T> 泛型介面的實作或 T 類型的 IComparable 介面。
範例:
List<string> Geek = new List<string>(); Geek.Add("Coronavirus"); Geek.Add("Election results"); Geek.Add("Kobe Bryant"); Geek.Add("Zoom"); Geek.Add("IPL"); Console.WriteLine("原來的List:"); foreach (string g in Geek) { // prints original List Console.WriteLine(g); } Console.WriteLine("n排序後的List:"); // sort the List Geek.Sort(); Console.WriteLine(); foreach (string g in Geek) { // prints the sorted List Console.WriteLine(g); } Console.WriteLine("n插入 India vs New Zealand:"); // insert "India vs New Zealand" in the List //"India vs New Zealand" insert into its original // position when the List is sorted int index = Geek.BinarySearch("India vs New Zealand"); if (index < 0) { Geek.Insert(~index, "India vs New Zealand"); } Console.WriteLine(); foreach (string g in Geek) { // prints the sorted list // after inserting "EFGH" Console.WriteLine(g); }
輸出:
B.BinarySearch(T, IComparer<T>)方法
用法:public int BinarySearch (T item, System.Collections.Generic.IComparer<T>? comparer);
參數:
item T
要尋找的物件。 參考類型的值可以是 null。
comparer IComparer<T>
比較項目時所要使用的 IComparer<T> 實作。
-或- null 表示使用預設比較子 Default。
傳回:
Int32
如果有找到 item,則為已排序的 List<T> 中 item 之以零為起始的索引,否則便為負數,此負數為大於 item 的下一個項目索引之位元補數,或者,如果沒有更大的項目,則為 Count 的位元補數。
例外狀況:
InvalidOperationException
comparer 為 null,而且預設比較子 Default 找不到 IComparable<T> 泛型介面的實作或 T 類型的 IComparable 介面。
範例:
下列範例是來自微軟的,但因為翻譯怪怪的,所以我重新翻譯了一下,範例示範方法多載 Sort(IComparer<T>) 和方法多載 BinarySearch(T, IComparer<T>) 。
這個範例會針對名為 DinoCompare 的字串定義替代比較子實作 IComparer<string> (在Visual Basic是 IComparer(Of String),在 Visual C++是 IComparer<String^> ) 泛型介面,比較子的運作方式如下:首先,會測試比較 null 值的,而且會將 null 參考視為小於非 null。 其次,會比較字串長度,而較長的字串會被視為較大的。 第三,如果長度相等,則會使用一般字串比較。
字串的 List<T> 會被建立,並填入四個字串,四個字串沒有特定的順序。 list 隨即顯示,並使用替代比較子排序,然後再次顯示。
BinarySearch(T, IComparer<T>)然後會使用方法多載來搜尋不在 list 中的數個字串,採用替代比較子。 Insert方法是用來插入字串。 這兩個方法位於名為的函式中 SearchAndInsert ,以及使用BinarySearch(T, IComparer<T>)傳回的索引值做位元補數 (在 C # 和 Visual C++ 中是用 ~ 運算子,在Visual Basic中使用 Xor -1 運算子)取得負數,並使用它作為插入新字串的索引。
using System; using System.Collections.Generic; public class DinoComparer: IComparer<string> { public int Compare(string x, string y) { if (x == null) { if (y == null) { // If x is null and y is null, they're // equal. return 0; } else { // If x is null and y is not null, y // is greater. return -1; } } else { // If x is not null... // if (y == null) // ...and y is null, x is greater. { return 1; } else { // ...and y is not null, compare the // lengths of the two strings. // int retval = x.Length.CompareTo(y.Length); if (retval != 0) { // If the strings are not of equal length, // the longer string is greater. // return retval; } else { // If the strings are of equal length, // sort them with ordinary string comparison. // return x.CompareTo(y); } } } } } public class Example { public static void Main() { List<string> dinosaurs = new List<string>(); dinosaurs.Add("Pachycephalosaurus"); dinosaurs.Add("Amargasaurus"); dinosaurs.Add("Mamenchisaurus"); dinosaurs.Add("Deinonychus"); Display(dinosaurs); DinoComparer dc = new DinoComparer(); Console.WriteLine("nSort with alternate comparer:"); dinosaurs.Sort(dc); Display(dinosaurs); SearchAndInsert(dinosaurs, "Coelophysis", dc); Display(dinosaurs); SearchAndInsert(dinosaurs, "Oviraptor", dc); Display(dinosaurs); SearchAndInsert(dinosaurs, "Tyrannosaur", dc); Display(dinosaurs); SearchAndInsert(dinosaurs, null, dc); Display(dinosaurs); } private static void SearchAndInsert(List<string> list, string insert, DinoComparer dc) { Console.WriteLine("nBinarySearch and Insert "{0}":", insert); int index = list.BinarySearch(insert, dc); if (index < 0) { list.Insert(~index, insert); } } private static void Display(List<string> list) { Console.WriteLine(); foreach( string s in list ) { Console.WriteLine(s); } } } /* This code example produces the following output: Pachycephalosaurus Amargasaurus Mamenchisaurus Deinonychus Sort with alternate comparer: Deinonychus Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "Coelophysis": Coelophysis Deinonychus Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "Oviraptor": Oviraptor Coelophysis Deinonychus Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "Tyrannosaur": Oviraptor Coelophysis Deinonychus Tyrannosaur Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "": Oviraptor Coelophysis Deinonychus Tyrannosaur Amargasaurus Mamenchisaurus Pachycephalosaurus */
C.BinarySearch(Int32, Int32, T, IComparer<T>)方法
用法:public int BinarySearch (int index, int count, T item, System.Collections.Generic.IComparer<T>? comparer);
參數:
index Int32 要搜尋範圍內之以零為起始的起始索引。
count Int32 搜尋範圍的長度。
item T 要尋找的物件。 參考類型的值可以是 null。
comparer IComparer<T> 比較項目時要使用的 IComparer<T> 實作,或 null 表示使用預設比較子 Default。
傳回:
Int32
如果有找到 item,則為已排序的 List<T> 中 item 之以零為起始的索引,否則便為負數,此負數為大於 item 的下一個項目索引之位元補數,或者,如果沒有更大的項目,則為 Count 的位元補數。例外狀況:
ArgumentOutOfRangeException index 小於 0。 -或- count 小於 0。
ArgumentException index 和 count 不代表 List<T> 中的有效範圍。
InvalidOperationException comparer 為 null,而且預設比較子 Default 找不到 IComparable<T> 泛型介面的實作或 T 類型的 IComparable 介面。
範例:
下列範例一樣取自微軟的範例,也是因為中文翻譯怪怪的,所以分享在這篇文章中,這個範例示範方法多載 Sort(Int32, Int32, IComparer<T>) 和方法多載 BinarySearch(Int32, Int32, T, IComparer<T>) 。
這個範例會針對名為 DinoCompare 的字串定義替代比較子,實作 IComparer<string>(Visual Basic 中以 IComparer(Of String),在 Visual C++ 則是以 IComparer<String^> 泛型介面中執行),比較子的運作方式如下:首先,會測試比較 null 值的,而且會將 null 參考視為小於非 null。 其次,會比較字串長度,而較長的字串會被視為較大的。 第三,如果長度相等,則會使用一般字串比較。
List<T>會建立字串的,並填入五個 herbivorous dinosaurs 和三個 carnivorous dinosaurs 的名稱。 在這兩個群組中,這些名稱不會有任何特定的排序次序。 隨即顯示 list、使用替代比較子排序 herbivores 的範圍,然後再次顯示 list。
BinarySearch(Int32, Int32, T, IComparer<T>)方法多載被用來搜尋 “Brachiosaurus” 的 herbivores 範圍。 找不到字串,且位補數 (在 C# 和 Visual C++ 中使用 ~ 運算子,而Visual Basic中使用 Xor -1方法)是負的, BinarySearch(Int32, Int32, T, IComparer<T>) 會用來做為插入新字串的索引。
using System; using System.Collections.Generic; public class DinoComparer: IComparer<string> { public int Compare(string x, string y) { if (x == null) { if (y == null) { // If x is null and y is null, they're // equal. return 0; } else { // If x is null and y is not null, y // is greater. return -1; } } else { // If x is not null... // if (y == null) // ...and y is null, x is greater. { return 1; } else { // ...and y is not null, compare the // lengths of the two strings. // int retval = x.Length.CompareTo(y.Length); if (retval != 0) { // If the strings are not of equal length, // the longer string is greater. // return retval; } else { // If the strings are of equal length, // sort them with ordinary string comparison. // return x.CompareTo(y); } } } } } public class Example { public static void Main() { List<string> dinosaurs = new List<string>(); dinosaurs.Add("Pachycephalosaurus"); dinosaurs.Add("Amargasaurus"); dinosaurs.Add("Mamenchisaurus"); dinosaurs.Add("Deinonychus"); Display(dinosaurs); DinoComparer dc = new DinoComparer(); Console.WriteLine("nSort with alternate comparer:"); dinosaurs.Sort(dc); Display(dinosaurs); SearchAndInsert(dinosaurs, "Coelophysis", dc); Display(dinosaurs); SearchAndInsert(dinosaurs, "Oviraptor", dc); Display(dinosaurs); SearchAndInsert(dinosaurs, "Tyrannosaur", dc); Display(dinosaurs); SearchAndInsert(dinosaurs, null, dc); Display(dinosaurs); } private static void SearchAndInsert(List<string> list, string insert, DinoComparer dc) { Console.WriteLine("nBinarySearch and Insert "{0}":", insert); int index = list.BinarySearch(insert, dc); if (index < 0) { list.Insert(~index, insert); } } private static void Display(List<string> list) { Console.WriteLine(); foreach( string s in list ) { Console.WriteLine(s); } } } /* This code example produces the following output: Pachycephalosaurus Amargasaurus Mamenchisaurus Deinonychus Sort with alternate comparer: Deinonychus Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "Coelophysis": Coelophysis Deinonychus Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "Oviraptor": Oviraptor Coelophysis Deinonychus Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "Tyrannosaur": Oviraptor Coelophysis Deinonychus Tyrannosaur Amargasaurus Mamenchisaurus Pachycephalosaurus BinarySearch and Insert "": Oviraptor Coelophysis Deinonychus Tyrannosaur Amargasaurus Mamenchisaurus Pachycephalosaurus */
c# list find 尋找符合的條件
你一定感到有點納悶,有了IndexOf跟Contains方法就可以尋找相符的項目,如果複雜點也可以用sort方法搭配BinarySearch來搜尋,實在不太懂Find方法有什麼必要性,不過有人有使用IndexOf跟BinarySearch做比較,大概在項目數70~100之間就會有轉折的不同,100個以上項目時,用sort方法搭配BinarySearch來搜尋會比較快,70個項目數以下使用IndexOf較快,這個實驗可以參閱List<T>线性查找和二分查找BinarySearch效率分析,那Find跟IndexOf呢?一樣都是使用線性的方法,或許也可以做個實驗來看看。
List<T>.Find(Predicate<T>) 方法的定義是這樣的:
命名空間:
System.Collections.Generic
組件:
mscorlib.dll, netstandard.dll
搜尋符合指定之述詞所定義的條件之項目,並傳回整個 List<T> 內第一個相符的項目。
我們一樣使用微軟的範例:
using System; using System.Collections.Generic; // Simple business object. A PartId is used to identify a part // but the part name can change. public class Part : IEquatable<Part> { public string PartName { get; set; } public int PartId { get; set; } public override string ToString() { return "ID: " + PartId + " Name: " + PartName; } public override bool Equals(object obj) { if (obj == null) return false; Part objAsPart = obj as Part; if (objAsPart == null) return false; else return Equals(objAsPart); } public override int GetHashCode() { return PartId; } public bool Equals(Part other) { if (other == null) return false; return (this.PartId.Equals(other.PartId)); } // Should also override == and != operators. } public class Example { public static void Main() { // Create a list of parts. List<Part> parts = new List<Part>(); // Add parts to the list. parts.Add(new Part() { PartName = "crank arm", PartId = 1234 }); parts.Add(new Part() { PartName = "chain ring", PartId = 1334 }); parts.Add(new Part() { PartName = "regular seat", PartId = 1434 }); parts.Add(new Part() { PartName = "banana seat", PartId = 1444 }); parts.Add(new Part() { PartName = "cassette", PartId = 1534 }); parts.Add(new Part() { PartName = "shift lever", PartId = 1634 }); ; // Write out the parts in the list. This will call the overridden ToString method // in the Part class. Console.WriteLine(); foreach (Part aPart in parts) { Console.WriteLine(aPart); } // Check the list for part #1734. This calls the IEquatable.Equals method // of the Part class, which checks the PartId for equality. Console.WriteLine("nContains: Part with Id=1734: {0}", parts.Contains(new Part { PartId = 1734, PartName = "" })); // Find items where name contains "seat". //符合條件的第一個object,找不到傳回 null Console.WriteLine("nFind: Part where name contains "seat": {0}", parts.Find(x => x.PartName.Contains("seat"))); // Check if an item with Id 1444 exists. //是否存在=> 存在回傳true Console.WriteLine("nExists: Part with Id=1444: {0}", parts.Exists(x => x.PartId == 1444)); /*This code example produces the following output: ID: 1234 Name: crank arm ID: 1334 Name: chain ring ID: 1434 Name: regular seat ID: 1444 Name: banana seat ID: 1534 Name: cassette ID: 1634 Name: shift lever Contains: Part with Id=1734: False Find: Part where name contains "seat": ID: 1434 Name: regular seat Exists: Part with Id=1444: True */ } }
另一個範例增加了FindIndex、FindAll、FindLast的使用
using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; namespace Find { class Program { private static string IDtoFind = "bk109"; private static List<Book> Books = new List<Book>(); public static void Main(string[] args) { FillList(); // Find a book by its ID. Book result = Books.Find( delegate(Book bk) { return bk.ID == IDtoFind; } ); if (result != null) { DisplayResult(result, "Find by ID: " + IDtoFind); } else { Console.WriteLine("nNot found: {0}", IDtoFind); } // Find last book in collection published before 2001. result = Books.FindLast( delegate(Book bk) { DateTime year2001 = new DateTime(2001,01,01); return bk.Publish_date < year2001; }); if (result != null) { DisplayResult(result, "Last book in collection published before 2001:"); } else { Console.WriteLine("nNot found: {0}", IDtoFind); } // Find all computer books. //符合條件的所有objects List<Book> results = Books.FindAll(FindComputer); if (results.Count != 0) { DisplayResults(results, "All computer:"); } else { Console.WriteLine("nNo books found."); } // Find all books under $10.00. results = Books.FindAll( delegate(Book bk) { return bk.Price < 10.00; } ); if (results.Count != 0) { DisplayResults(results, "Books under $10:"); } else { Console.WriteLine("nNo books found."); } // Find index values. //符合條件的第一個index,找不到傳回 -1 Console.WriteLine(); int ndx = Books.FindIndex(FindComputer); Console.WriteLine("Index of first computer book: {0}", ndx); ndx = Books.FindLastIndex(FindComputer); Console.WriteLine("Index of last computer book: {0}", ndx); int mid = Books.Count / 2; ndx = Books.FindIndex(mid, mid, FindComputer); Console.WriteLine("Index of first computer book in the second half of the collection: {0}", ndx); ndx = Books.FindLastIndex(Books.Count - 1, mid, FindComputer); Console.WriteLine("Index of last computer book in the second half of the collection: {0}", ndx); } // Populates the list with sample data. private static void FillList() { // Create XML elements from a source file. XElement xTree = XElement.Load(@"c:tempbooks.xml"); // Create an enumerable collection of the elements. IEnumerable<XElement> elements = xTree.Elements(); // Evaluate each element and set set values in the book object. foreach (XElement el in elements) { Book book = new Book(); book.ID = el.Attribute("id").Value; IEnumerable<XElement> props = el.Elements(); foreach (XElement p in props) { if (p.Name.ToString().ToLower() == "author") { book.Author = p.Value; } else if (p.Name.ToString().ToLower() == "title") { book.Title = p.Value; } else if (p.Name.ToString().ToLower() == "genre") { book.Genre = p.Value; } else if (p.Name.ToString().ToLower() == "price") { book.Price = Convert.ToDouble(p.Value); } else if (p.Name.ToString().ToLower() == "publish_date") { book.Publish_date = Convert.ToDateTime(p.Value); } else if (p.Name.ToString().ToLower() == "description") { book.Description = p.Value; } } Books.Add(book); } DisplayResults(Books, "All books:"); } // Explicit predicate delegate. private static bool FindComputer(Book bk) { if (bk.Genre == "Computer") { return true; } else { return false; } } private static void DisplayResult(Book result, string title) { Console.WriteLine(); Console.WriteLine(title); Console.WriteLine("n{0}t{1}t{2}t{3}t{4}t{5}", result.ID, result.Author, result.Title, result.Genre, result.Price, result.Publish_date.ToShortDateString()); Console.WriteLine(); } private static void DisplayResults(List<Book> results, string title) { Console.WriteLine(); Console.WriteLine(title); foreach (Book b in results) { Console.Write("n{0}t{1}t{2}t{3}t{4}t{5}", b.ID, b.Author, b.Title, b.Genre, b.Price, b.Publish_date.ToShortDateString()); } Console.WriteLine(); } } public class Book { public string ID { get; set; } public string Author { get; set; } public string Title { get; set; } public string Genre { get; set; } public double Price { get; set; } public DateTime Publish_date { get; set; } public string Description { get; set; } } }
※2022/05/19
今天再補充一部list find c#的Youtube教學影片《C# List Searching and Finding》,我是有點聽不懂但可以看他的操作來學習
總結
這篇c#教學文章說明如何使用 List<T> 類別來操作物件集合,還有分享如何新增、搜尋、排序及反轉排序 list 中的項目,這是最近大叔用C# 5年的心得,以上的分享或是翻譯有錯誤,也請各位告知或糾正,謝謝~~^^!
之前有人在問c# stringlist的用法,後來看到微軟的一個頁面上有提到StringList Class的使用,但這是在Microsoft.TeamFoundation.Build.WorkFlow.Activities命名空間中使用,是07/02/2014的文章,看起來也沒有更新了,所以微軟有這樣的提醒訊息:
We’re no longer updating this content regularly. Check the Microsoft Product Lifecycle for information about how this product, service, technology, or API is supported.
建議各位使用新的版本或是別的版本。
新手開發人員、剛接觸 C# 的開發人員,以及經驗豐富的 C# / .Net 開發人員想要學習 C# 程式設計的也可以上c#教學看。
學 C# 敢找機電整合工程師的工作嗎?
c#教學:
2 則留言