List<T>
- 实现了
IList,ICollection,IEnumerable,IList<T>,ICollection<T>,IEnumerable<T> - 元素类型必须为T
- 其实现中,其实是在用一个T类型的数组
ArrayList(与List<T>对比)
- 非泛型列表
- 可以将任何Object类型作为元素
List<T>的初始化
//创建一个空列表
var racers = new List<Racer>();
List<T>的容量
Capacity属性可以查看容量- 每次,会将列表容量重设为原来的2倍
- 空列表添加进1元素,容量变为4
- 添加到第5个元素,容量变为8
- 添加到第9个元素,容量变为16
- 每次容量改变,都要重新分配到一个新的内存块中。这时,会创建一个新数组,将Array.Copy()将List内部的旧数组复制到新数组。
为了节省复制数组的时间消耗,若提前知道List的元素个数,就可以用构造函数指定其容量。
var racers = new List<Racer>(10);
为了节省多余开辟出来的内存,若已经将所有元素加入列表,并不再加了,就可以调用TrimExcess(),去除不需要的容量
racers.TrimExcess();
List<T> 添加元素
方法一:初始化器:
var graham = new Racer(7, "Graham", "Hill", "UK", 14);
var emerson = new Racer(13, "Emerson", "Fittipaldi", "Brazil", 14);
var mario = new Racer(16, "Mario", "Andretti", "USA", 12);
var racers = new List<Racer> { graham, emerson, mario };
方法二:Add():
racers.Add(new Racer(24, "Michael", "Schumacher", "Germany", 91));
racers.Add(new Racer(27, "Mika", "Hakkinen", "Finland", 20));
方法三:AddRange():
- 参数是
IEnumerable<T>对象,所以数组可以。
racers.AddRange(new Racer[] {
new Racer(14, "Niki", "Lauda", "Austria", 25),
new Racer(21, "Alain", "Prost", "France", 51)});
方法四:传递IEnumerable<T>给构造函数:
var racers = new List<Racer>{
new Racer[] {
new Racer(14, "Niki", "Lauda", "Austria", 25),
new Racer(21, "Alain", "Prost", "France", 51)};
List<T> 插入元素
方法一:Insert()
racers.Insert(3, new Racer(6, "Phil", "Hill", "USA", 3));
方法二:InsertRange()
List<T> 访问元素
方法一:索引器
- 因为实现了
IList和IList<T>
for (int i = 0; i < racers.Count; i++)
{
Console.WriteLine(racers[i]);
}
方法二:foreach
- 因为实现了
IEnumerable接口
foreach (var r in racers)
{
Console.WriteLine(r);
}
List<T> 删除元素
方法一:利用索引 RemoveAt()
- 比较快速
//删除第三个元素
racers.RemoveAt(3)
方法二:利用索引 RemoveRange(开始索引,元素个数)
racers.RemoveAt(3, 5)
方法三:传递要删除的元素
IndexOf(传递的元素)获取,与之相等的元素,的索引IndexOf()在集合中搜索,与传递的元素,相等的元素:- 检查元素类型是否实现了
IEquatable<T>接口。 - 如果是,则调用这个接口的
Equals方法。 - 如果否,则调用
Object类的Equals方法。如此找到相等的元素。
- 检查元素类型是否实现了
- 再用该索引,删除该元素
方法四:删除满足特定条件的元素
RemoveAll( Predicate<T> )
方法五:删除所有元素
ICollection<T>定义的Clear()方法
List<T> 搜索元素
获得要查找的元素的索引:(第一个匹配的)(可以搜索相等的)
IndexOf(元素)(从前向后查找)LastIndexOf(元素)(从后向前查找) 获得要查找的元素的索引:(第一个匹配的)(可以搜索有某个特性的)FindIndex(Predicate<元素类型> match)(从前向后查找)FindLastIndex(Predicate<元素类型> match)(从后向前查找) 获得要查找的元素:(第一个匹配的)(可以搜索有某个特性的)Find(Predicate<元素类型> match)(从前向后查找)FindLast(Predicate<元素类型> match)(从后向前查找) 获得要查找的元素:(所有匹配的)(可以搜索有某个特性的)FindAll(Predicate<元素类型> match)(从前向后查找)
IndexOf(元素)详解:
- 若找到,返回元素索引
- 若没找到,返回
-1判定是否找到: - 检查元素类型是否实现了
IEquatable<T>接口。 - 如果是,则调用这个接口的
Equals方法。 - 如果否,则调用
Object类的Equals方法。如此找到相等的元素。
FindIndex(Predicate<元素类型> match)详解:
对每一个元素,执行委托所代表的方法
- 返回true, 表示匹配到满足这个特定条件的元素
- 返回false, 表示没匹配到满足这个特定条件的元素
Predicate<T>是个委托,public delegate bool Predicate<T>(T obj);
int index2 = racers.FindIndex(new FindCountry("Finland").FindCountryPredicate);
public class FindCountry
{
public FindCountry(string country) => _country = country;
private readonly string _country;
public bool FindCountryPredicate(Racer racer) => racer?.Country == _country;
}
或者Predicate<元素类型> 用lamda表达式:
int index3 = racers.FindIndex(r => r.Country == "Finland");
FindAll(Predicate<元素类型> match) 示例:
List<Racer> bigWinners = racers.FindAll(r => r.Wins > 20);
foreach (Racer r in bigWinners)
{
Console. WriteLine($"{r:A}");
}
List<T> 排序
方法一:public void List<T>.Sort()
- 元素类型
T,只有实现了IComparable<T>接口,才能使用这个不带参数的Sort()方法
public class Racer : IComparable<Racer>
{
//...
public int CompareTo(Racer other)
{
int compare = LastName?.CompareTo(other?.LastName) ?? -1;
if (compare == 0)
{
return FirstName?.CompareTo(other?.FirstName) ?? -1;
}
return compare;
}
}
- 如果不想用元素类型
T默认支持的排序方式,那就要用其他方法:
方法二:public void List<T>.Sort(Comparison<T>)
Comparison<T>是一个委托,public delegate int Comparison<T>(T x, T y)- 第一个参数比第二个参数小,就返回一个小于0的值
- 第一个参数比第二个参数大,就返回一个大于0的值
- 两个参数一样,就返回0
racers.Sort((r1, r2) => r2.Wins.CompareTo(r1.Wins))
方法三:public void List<T>.Sort(IComparer<T>)
- 返回值小于
0,代表第一个参数小于第二个参数 - 返回值大于
0,代表第一个参数大于第二个参数
null的位置在其他任何元素之前
- 第一个参数为
null, 返回值为-1 - 第二个参数为
null, 返回值为1
public class RacerComparer : IComparer<Racer>
{
private CompareType _compareType;
public RacerComparer(CompareType compareType) =>
_compareType = compareType;
public int Compare(Racer x, Racer y)
{
if (x == null && y == null) return 0;
if (x == null) return -1;
if (y == null) return 1;
int result;
switch (_compareType)
{
case CompareType.FirstName:
result = string.Compare(x.FirstName, y.FirstName);
break;
case CompareType.LastName:
result = string.Compare(x.LastName, y.LastName);
break;
case CompareType.Country:
result = string.Compare(x.Country, y.Country);
if (result == 0)
{
result = string.Compare(x.LastName, y.LastName);
}
break;
case CompareType.Wins:
result = x.Wins.CompareTo(y.Wins);
break;
default:
throw new ArgumentException("Invalid Compare Type");
}
return result;
}
}
方法四:public void List<T>.Sort(Int32, Int32, IComparer<T>)
方法五: Reverse()方法来逆转整个集合的顺序
List<T>转换成只读集合ReadOnlyCollection<T>
List<T>的AsReadOnly()方法,返回ReadOnlyCollection<T>类型对象。
示例 Racer类
public class Racer : IComparable<Racer>, IFormattable
{
public Racer(int id, string firstName, string lastName, string country, int wins)
{
Id = id;
FirstName = firstName;
LastName = lastName;
Country = country;
Wins = wins;
}
public Racer(int id, string firstName, string lastName, string country)
: this(id, firstName, lastName, country, wins: 0)
{ }
public int Id { get; }
public string FirstName { get; }
public string LastName { get; }
public string Country { get; }
public int Wins { get; set; }
public override string ToString() => $"{FirstName} {LastName}";
public string ToString(string format, IFormatProvider formatProvider)
{
if (format == null) format = "N";
switch (format.ToUpper())
{
case null:
case "N": // name
return ToString();
case "F": // first name
return FirstName;
case "L": // last name
return LastName;
case "W": // Wins
return $"{ToString()}, Wins: {Wins}";
case "C": // Country
return $"{ToString()}, Country: {Country}";
case "A": // All
return $"{ToString()}, Country: {Country} Wins: {Wins}";
default:
throw new FormatException(String.Format(formatProvider,
"Format {0} is not supported", format));
}
}
public string ToString(string format) => ToString(format, null);
public int CompareTo(Racer other)
{
int compare = LastName?.CompareTo(other?.LastName) ?? -1;
if (compare == 0)
{
return FirstName?.CompareTo(other?.FirstName) ?? -1;
}
return compare;
}
}