列表是和数组最像的结构了。使用int索引获取和访问值。但是列表的容量是可变的。
int[] arr = { 1,2,3};
List<int> list = new List<int>(arr);
List<int> list2 = new List<int>();
构造器中使用一个序列,会直接复刻那种序列的状态。
列表可以像数组一样使用索引器访问和修改元素。
list[0] = 20;
int b = list[1];
list[2]++;
列表的改变容量必须和添加/删除元素同时进行。
list.Add(1);
list.AddRange(arr);
AddRange可以一次性添加一整个序列的元素。
list.Insert(1,20);
list.InsertRange(1,arr);
第一个参数是int类型,表示索引。第二个参数是泛型参数的类型,或他的序列。
插入的数据会占据填入的索引,之后的元素全部向后顺位。
list.Remove(1);
list.RemoveAt(1);
Remove是查找相等的元素,在这里也就是删除等于1的元素。
如果有多个相等的元素,只会删除查找到的第一个元素。
会返回一个bool值,指示是否真的删除了元素(查找到了相等的元素)。
RemoveAt是删除指定索引处的元素。
list.RemoveRange(3, 2);
list.RemoveAll(i => i == 20);
现在c#的范围运算还没有普及开来。
大部分牵扯到范围的事,都是开始索引+往后连续的长度。
比如这里的RemoveRange(3, 2),就是指从索引3开始数,数两个数。也就是删除掉索引为3,4的值。
RemoveAll则是一个委托,删除所有符合条件的值。
大多数数据集合都是在背后有一个数组存放数据的。
因为数组这种最基本的数据结构比较省空间,而且找的快。
如果添加元素时,长度不够了,那么会建立一个新数组,把旧值复制进去。
如果长度过长,那么就会浪费一堆空间。
如果没有设置初始长度,会以0为基础值,也就是不声明数组。在添加内容后,初始声明长度为4的数组。
如果构造器填入序列或一个数量,那么长度和序列长度或参数一致。
在超出大小后,会声明当前长度*2的数组。
使用Capacity属性可以获得或调整数组长度。当然如果长度比需要的长度还小会报错。
TrimExcess方法在所需长度少于数组长度90%时,把数组长度设置为和所需长度一致。
Clear方法会清空元素,但是保留背后的数组。
想较而言如果直接新建一个List,要重新配置数组。
List的排序方法直接从实例上调用。
甚至如果他无法排序,还可以使用一个委托,指定如何排序。
class Student
{
public string name;
public int age;
public int id;
}
Student[] stArr = new Student[]
{
new() { name = "小明", age = 12 ,id=1 },
new() { name = "小红", age = 13 ,id=2 },
new() { name = "小丽", age = 12 ,id=3 }
};
List<Student> list = new List<Student>(stArr);
list.Sort();
list.Sort((a, b) => a.id - b.id);
这个委托有两个参数,指代比较的两个元素。
返回结果是一个整数,如果小于0,则第一个参数排在第二个参数前面。
如果大于0,则排在后面。
如果等于0,他们并列。但是c#使用的排序方法是不稳定的排序,并列的元素在排序后无法预测谁在前面。
Reverse方法。和LINQ一样,不过会对自己身上生效。
Exists方法,等同LINQ的Any方法,填入一个委托,查看是否有满足条件的元素
TrueForAll方法,等同LINQ的All方法,填入一个委托,查看元素是否全部满足条件。
IndexOf方法,一个参数
字典也使用索引访问内容。但索引不要求数字,可以是任何类型。
因此也不带顺序。例如如果你使用数字做索引,那么可以凭空出现索引10,而0-9都没有。
class Student
{
public string name;
public int age;
}
Dictionary<string, Student> dic = new Dictionary<string, Student>();
第一个泛型是键(Key)类型,充当索引类型。
第二个泛型是值(Value)类型,通过索引访问的类型。
dic["小明"] = new Student() { name = "小明", age = 12 };
dic["小红"] = null;
使用索引指定新值,可以添加或更新元素。
索引不能是null,虽然写起来不会报错,但运行的时候会报错。
一个弊端是,有时候不希望在已经存在值的时候去更改值。
可以使用TryAdd方法尝试添加值,如果这个索引已经存在,那么无事发生。
dic.TryAdd("小明", null);
这个方法会返回一个bool值,指示是否添加成功(是否找到相同索引)。
索引和值必须成对出现,所以这个方法需要两个参数。
使用索引也可以访问元素
Console.WriteLine(dic["小明"].name);
Student st = dic["小红"];
前提是字典已经收录过这个索引。如果没有那么会报错。
如果你无法确定是否存在这个索引,可以使用TryGetValue方法尝试获取值。
dic.TryGetValue("小绿", out Student st2);
输出值以out参数形式输出。方法自己的返回值是bool,指示是否成功找到值。
如果没有找到,输出值是这种类型的默认值。
字典的键,和值,可以单独作为一个集合使用。
使用属性访问他们。不过,这种集合类型是字典的嵌套类,既不是数组,也不是列表,或是其他的东西。
他们的内容不保证顺序,不过保证相同索引下,键集合和值集合中的元素是匹配的。
在对字典使用foreach或LINQ时,会生成键值对结构。
这个结构只有两个属性,键和值。并且他具有析构方法,可以析构成元组。
多维数组,类似数组的数组。
但是多个长度和逗号都写在一个中括号内。
int[,,] arr = new int[6, 8, 10];
数组的数组,各数组的长度可能不同。也被称为交错数组。
多维数组各维度长度是相同的。一般来说在确定能装满的情况下才会使用。
多维数组不享受单维数组的操作。例如Array.Sort的排序方法,对多维数组会报错。
例如无法使用LINQ。
多维数组也使用索引访问,需要保证各个维度上的索引都没有越界。
arr[1, 2, 3] = 16;
int c = arr[2, 4, 8];
多维数组仍然可以foreach,但不是通过IEnumerable接口,而是通过IEnumerator接口。
所以多维数组没有LINQ方法。
多维数组使用for循环时,可以使用GetLength方法获得各个维度的长度。索引从0开始。
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
for (int k = 0; k < arr.GetLength(2); k++)
{
Console.WriteLine(arr[i, j, k]);
}
}
}