本文涉及:
1.對列表中的元素進行“批量類型轉換”
2.對列表中每個元素的“加工”
3.對列表元素的排序
4.檢測列表中的元素是否滿足某個條件
5.在列表中尋找元素
註:上述的操作並不是針對數組,或者List..而是有通用性,一般實現了IEnumerable<T>介面的列表都可具有下面的方法。
一、對列表中的元素進行“批量類型轉換”
在某些情況下可能會需要將列表中的所有元素轉換為另一個類型,這個工作可以通過調用 ConvertAll 方法實現。
public List<TOutput> ConvertAll<TOutput>(
Converter<T, TOutput> converter
)
上述方法的第2個參數是一個委託,其定義如下:
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter);
通過設計一個滿足此委託要求的數組元素類型轉換方法,ConvertAll 方法可以將一個集合中的所有元素轉換類型後再複製到一個新的集合中。
範例程式碼:
ConvertAll方法範例程式碼
using System;
using System.Collections.Generic;
public class Example
{
public class PointF
{
public PointF(float x1, float y1)
{
this.X1 = x1;
this.Y1 = y1;
}
public float X1;
public float Y1;
}
public class Point
{
public Point(int x2, int y2)
{
this.X2 = x2;
this.Y2 = y2;
}
public int X2;
public int Y2;
}
public static void Main()
{
List<PointF> lpf = new List<PointF>();
lpf.Add(new PointF(27.8F, 32.62F));
lpf.Add(new PointF(99.3F, 147.273F));
lpf.Add(new PointF(7.5F, 1412.2F));
Console.WriteLine();
foreach (PointF p in lpf)
{
Console.WriteLine(p.X1.ToString()+ "" + p.Y1.ToString());
}
//調用方式一:標準寫法
List<Point> lp = lpf.ConvertAll(
new Converter<PointF, Point>(PointFToPoint));
//調用方式二:使用匿名方法(可以省去單獨定義的PointFToPoint方法)
//使用匿名方法需要注意,方法體以 delegate 關鍵字打頭,
//其後是參數列表,緊接著在一對大括弧內書寫方法代碼,最後以分號結尾
List<Point> lp2 = lpf.ConvertAll(
new Converter<PointF, Point>(
delegate(PointF pf)
{
return new Point((int)pf.X1, (int)pf.Y1);
}));
//調用方式三:使用Lambda運算式再次精簡代碼
List<Point> lp3 = lpf.ConvertAll(
new Converter<PointF, Point>(
(pf) => { return new Point((int)pf.X1, (int)pf.Y1); }));
Console.WriteLine();
foreach (Point p in lp)
{
Console.WriteLine(p.X2.ToString() + "" + p.Y2.ToString());
}
Console.ReadKey();
}
//這裡定義了一個轉換方法,與Converter委託相對應。我們可以叫這個方法為“元素轉換器”
public static Point PointFToPoint(PointF pf)
{
return new Point(((int)pf.X1), ((int)pf.Y1));
}
}
/* This code example produces the following output:
{X=27.8, Y=32.62}
{X=99.3, Y=147.273}
{X=7.5, Y=1412.2}
{X=27,Y=32}
{X=99,Y=147}
{X=7,Y=1412}
*/
Converter 委託是C# 裡面位於System命名空間下的系統委託,主要用來轉換元素類型。
二、對列表中每個元素的“加工”
一般我們要對集合中的元素逐個進行同樣處理工作時,我們會寫一個foreach迴圈來處理,但這樣造成了代碼可讀性低下。其實.net中為我們提供了foreach<T>方法
方法原型如下:
public void ForEach(
Action<T> action
)
其參數是一個action委託,它引用“施加於”每個數組元素的“處理方法”。
範例程式碼:
foreach方法樣本
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<String> names = new List<String>();
names.Add("Bruce");
names.Add("Alfred");
names.Add("Tim");
names.Add("Richard");
//這裡迴圈list每個元素,調用print方法
//調用方法一
names.ForEach(Print);
//調用方法二:匿名方法
names.ForEach(delegate(String name)
{
Console.WriteLine(name);
});
//調用方式三:使用 Lambda運算式精簡代碼,可以省略Print方法。
names.ForEach(r => Console.WriteLine(r));
Console.ReadKey();
}
private static void Print(string s)
{
Console.WriteLine(s);
}
}
/* This code will produce output similar to the following:
* Bruce
* Alfred
* Tim
* Richard
* Bruce
* Alfred
* Tim
* Richard
*/
三、對列表元素的排序
集合的排序前面的日記都有記載。詳情見前面的日記。
這裡做一下總結:
MSDN上List有如下的sort重載:
如果調用無參的sort()方法,那麼要求集合中的元素要實現 System.IComparable 介面,否則此方法會拋出InvalidOperationException異常。
如果集合的元素沒有實現IComparable介面,則可以調用Sort(IComparer<T>),這時我們要建立一個類實現IComparer介面作為比較子來完成排序。
或者更為簡單些,不需要定義一個比較子,直接給sort方法提供一個用於"比較兩對象”大小的方法即可---實現Comparison<T>委託。
Comparison委託範例程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SortObjectArray
{
class Program
{
static void Main(string[] args)
{
MyClass[] Objs = new MyClass[10];
Random ran=new Random();
for (int i = 0; i < 10; i++)
Objs[i] = new MyClass { Value = ran.Next(1, 100) };
Comparison<MyClass> WhoIsGreater = delegate(MyClass x, MyClass y)
{
if (x.Value > y.Value)
return 1;
else
if (x.Value == y.Value)
return 0;
else
return -1;
};
Array.Sort<MyClass>(Objs,WhoIsGreater);
Array.ForEach<MyClass>(Objs,(obj)=>{Console.WriteLine(obj.Value);});
Console.ReadKey();
}
}
class MyClass
{
public int Value;
}
}
四、關於Prddicate<T>委託
使用該委託可以實現很多實現,比如:
A.檢測列表中的元素是否滿足某個條件 TrueForAll<T>
B.在集合中尋找元素 Exists<T>
C.尋找滿足條件的元素 Find<T> FindLast<T> FindAll<T>
D.尋找滿足條件的元素的索引 FindIndex
.......等等
如果 集合
中的每個元素都與指定的謂詞所定義的條件相匹配,則為 true;否則為 false。 如果列表不包含任何元素,則傳回值為 true。
Predicate<T>是一個委託,它引用一個返回bool值的方法,此方法代表集合元素必須滿足的條件。
範例程式碼
using System;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
List<string> dinosaurs = new List<string>();
dinosaurs.Add("Compsognathus");
dinosaurs.Add("Amargasaurus");
dinosaurs.Add("Oviraptor");
dinosaurs.Add("Velociraptor");
dinosaurs.Add("Deinonychus");
dinosaurs.Add("Dilophosaurus");
dinosaurs.Add("Gallimimus");
dinosaurs.Add("Triceratops");
Console.WriteLine();
foreach(string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nTrueForAll(EndsWithSaurus): {0}",
dinosaurs.TrueForAll(EndsWithSaurus));
Console.WriteLine("\nFind(EndsWithSaurus): {0}",
dinosaurs.Find(EndsWithSaurus));
Console.WriteLine("\nFindLast(EndsWithSaurus): {0}",
dinosaurs.FindLast(EndsWithSaurus));
Console.WriteLine("\nFindAll(EndsWithSaurus):");
List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);
foreach(string dinosaur in sublist)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine(
"\n{0} elements removed by RemoveAll(EndsWithSaurus).",
dinosaurs.RemoveAll(EndsWithSaurus));
Console.WriteLine("\nList now contains:");
foreach(string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nExists(EndsWithSaurus): {0}",
dinosaurs.Exists(EndsWithSaurus));
}
// Search predicate returns true if a string ends in "saurus".
private static bool EndsWithSaurus(String s)
{
if ((s.Length > 5) &&
(s.Substring(s.Length - 6).ToLower() == "saurus"))
{
return true;
}
else
{
return false;
}
}
}
/* This code example produces the following output:
Compsognathus
Amargasaurus
Oviraptor
Velociraptor
Deinonychus
Dilophosaurus
Gallimimus
Triceratops
TrueForAll(EndsWithSaurus): False
Find(EndsWithSaurus): Amargasaurus
FindLast(EndsWithSaurus): Dilophosaurus
FindAll(EndsWithSaurus):
Amargasaurus
Dilophosaurus
2 elements removed by RemoveAll(EndsWithSaurus).
List now contains:
Compsognathus
Oviraptor
Velociraptor
Deinonychus
Gallimimus
Triceratops
Exists(EndsWithSaurus): False
*/