集合和数组集合的概念,以及区别:
数组是集合,但集合不一定是数组。
数组存储的类型不限制。集合存储的类型只能是引用类型。
数组(一般是相同数据类型,但object[]数组元素类型可以不同)的元素按一定顺序排列集合。
数组在添加,插入,删除等比方便,说明数组不是链表,但数组的读取(查询)速度比集合快。
集合是线性表,在插入,添加,删除数据时比较方面,性能比数组高。
C#中的集合(Collection)和数组(Array)是两种不同的数据结构,它们之间有以下主要区别:
- 定义方式不同:集合是使用集合类定义的,如List或HashSet。数组是使用类型和大小显式定义的。
- 大小不同:数组的大小在创建后无法更改,而集合的大小可以根据我们的需要动态增长。
- 内存布局不同:数组在内存中是连续的,而集合通常不是。
- 性能不同:访问数组元素通常比访问集合元素快,因为集合元素访问时可能需要进行装箱和拆箱操作。
- 索引访问:数组可以通过索引直接访问元素,而集合则需要使用迭代器或者在.NET 2.0及以上版本中使用foreach循环。
- 数据类型不同:数组可以存储基本数据类型(值类型),也可以存储引用类型,【而集合只能存储引用类型】,因为它们都继承自System.Object。
重要接口:
public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable
数组实现了6个接口,前4个接口很重要
ICloneable接口控制克隆,复制对象
IList列表接口,控制对象操作(添加,删除等)
IEnumerable可枚举对象的接口,控制是对象的循环
ICollection集合接口,控制复制对象
public interface IList :ICollection,IEnumerable 说明列表也是集合的一种。
public class ArrayList:IList,ICollection,IEnumerable,ICloneable
Public class List<T>:IList<T>,ICollection<T>,IEnumerable<T>, IEnumerable,IList,ICollection,IReadOnlyList<T>,IReadOnlyCollection<T>
集合和列表(List<>类)的对比:
列表:表示可通过索引访问的对象的强类型列表。 提供用于对列表进行搜索、排序和操作的方法
List<T>类是类的泛型等效项 ArrayList 。 它 IList<T> 通过使用大小根据需要动态增加的数组来实现泛型接口。
-
定义和实现:
- 集合:在C#中,集合是一个泛指,可以是数组、列表、字典、栈、队列等。集合是.NET Framework中System.Collections命名空间下的一个接口或类。
- 列表:列表是集合的一种具体实现,是泛型集合(List<T>),属于System.Collections.Generic命名空间。它提供了一种灵活的方式来存储和管理有序的数据项。
-
性能:
- 集合:性能取决于具体的集合类型。例如,ArrayList(非泛型集合)在添加和删除项时可能需要调整大小,这可能导致性能下降。
- 列表:列表提供了快速的索引访问,因为它是基于数组实现的。添加和删除元素通常很快,尤其是当列表未满时。
-
类型安全:
- 集合:非泛型集合(如ArrayList)不是类型安全的,可以存储任何类型的对象。
- 列表:列表是类型安全的,只能存储指定类型的元素。
-
灵活性:
- 集合:某些集合类型(如字典)提供了键值对的存储方式,这在某些场景下非常有用。
- 列表:列表主要用于存储有序的元素集合,不支持键值对。
-
功能:
- 集合:不同的集合类型提供不同的功能。例如,队列(Queue)和栈(Stack)分别提供了先进先出(FIFO)和后进先出(LIFO)的数据结构。
- 列表:列表提供了丰富的方法来添加、删除、查找和排序元素。
-
内存使用:
- 集合:某些集合类型可能会使用更多的内存来存储额外的信息,例如字典存储键和值的映射。
- 列表:列表通常使用较少的内存,因为它只存储元素本身。
-
线程安全:
- 集合:大多数集合类型不是线程安全的,需要额外的同步机制来保证线程安全。
- 列表:同样,List<T>也不是线程安全的。如果需要在多线程环境中使用,可以使用
List<T>
的线程安全版本,如ConcurrentBag<T>
。
ArrayList(非泛型集合类)
在C#中,ArrayList
是一个非泛型集合类,属于 System.Collections
命名空间。它提供了一种灵活的方式来存储和管理对象的有序集合。ArrayList
是一种动态数组,可以根据需要自动调整其大小。
public class ArrayList : IList, ICollection,IEnumerable, ICloneable
IList列表,ICollection集合
IEnumerable可枚举,可迭代,可循环
ICloneable可克隆,可复制
ArrayList arrayList1 = new ArrayList();//没有指定容量(常用)
ArrayList arrayList2 = new ArrayList(3); //指定容量,提醒: 没有存储任何的项,长度还是0
ArrayList arrayList3 = new ArrayList(new int[] {1,2,3});//放一个实现ICollection接口的集合
-
动态数组:
ArrayList
可以自动调整其大小以适应添加的元素数量。这使得它在需要存储不确定数量的元素时非常方便。 -
类型不安全:
ArrayList
可以存储任何类型的对象,因为它的元素类型是object
。这意味着在使用元素时,可能需要进行类型转换,这可能会引入运行时错误。 -
添加和删除元素:
ArrayList
提供了Add
和Remove
方法来添加和删除元素。当添加元素时,如果数组已满,ArrayList
会自动创建一个新的数组并将旧数组的元素复制到新数组中。注意:注意装箱,支持多种数据类型,取值时要拆箱。//添加 arrayList1.Add(1); arrayList1.Add("ac"); arrayList1.Add(true); //删除 arrayList1.Remove("ac");//按值删除 arrayList1.Remove(3);//按索引删除,有可能索引越界
-
Rang范围,可以一次添加多个。
arrayList1.AddRange(new object[] {"hello",false,213}); arrayList1.AddRange(new List<int> {1,2,3 }); arrayList1.AddRange(new Dictionary<string, string>() { {"key1","value1" }, {"key2","value2" } });
-
索引访问:可以通过索引访问
ArrayList
中的元素,就像访问数组一样。索引从零开始。Console.WriteLine(arrayList1.IndexOf(1)); // 0 Console.WriteLine(arrayList1.IndexOf("abc")); // 1 Console.WriteLine(arrayList1.IndexOf(200)); // -1 Console.WriteLine(arrayList1.LastIndexOf(1)); // 0 Console.WriteLine(arrayList1.LastIndexOf("abc")); // 1 Console.WriteLine(arrayList1.LastIndexOf(200)); // -1
-
容量和大小:
ArrayList
有一个Capacity
属性,表示可以存储的最大元素数。还有一个Count
属性,表示当前存储的元素数。 -
排序:
ArrayList
提供了Sort
方法,可以对集合中的元素进行排序。 -
查找:可以使用
IndexOf
方法查找元素在ArrayList
中的位置。 -
复制:可以使用
CopyTo
方法将ArrayList
中的元素复制到一个数组中。 -
同步:
ArrayList
不是线程安全的。如果你需要在多线程环境中使用它,可以使用ArrayList.Synchronized
方法创建一个线程安全的ArrayList
。 -
清空
arrayList1.Clear();
实例:
using System;
using System.Collections;
class Program
{
static void Main()
{
ArrayList list = new ArrayList();
// 添加元素
list.Add("Hello");
list.Add(123);
list.Add(DateTime.Now);
// 访问元素
Console.WriteLine(list[0]); // 输出 "Hello"
Console.WriteLine(list[1]); // 输出 123
Console.WriteLine(list[2]); // 输出当前日期和时间
// 删除元素
list.Remove(123);
// 显示元素
foreach (var item in list)
{
Console.WriteLine(item);
}
// 获取元素数量
Console.WriteLine("Count: " + list.Count);
// 获取最大容量
Console.WriteLine("Capacity: " + list.Capacity);
}
}
LIst列表
列表List对象,也是集合,并且是最流行集合
List列表中的数据类型是统一的
List<int>整体是一个类型,复合类型,List也是类型,int也是类型 <T>表示未知类型
也称泛型列表。和ArrayList集合最大区别:List列表中的项类型是统一的,而ArrayList集合中的项类型可以不同。
定义(格式):List<数据类型,类> 声明名字=new List<数据类型,类>(){值1,值2,值3};
List<int> list1 = new List<int>() { 1,1,1};
List<string> list2 = new List<string>() { "abc" };
Student one = new Student() { Id = 1, Name = "张三1" };
List<Student> student1 = new List<Student>() {
one,
new Student(){ Id=2,Name="张三1"},
new Student(){ Id=3,Name="张三2"},
};
1.查询数据:
FindAll()正向查多项,Find()正向查一项,FindLast()倒查一项
List<Student> stus = student1.FindAll(stu => stu.Name == "张三1");
Student stu1 = student1.Find(stu => stu.Name == "张三1");
Student stu2 = student1.FindLast(stu => stu.Name == "张三1");
Console.WriteLine(stu1.Id);
Console.WriteLine(stu2.Id);
2.查索引
IndexOf(), LastIndexOf(), FindIndex(), FindLastIndex()
int index1 = student1.IndexOf(one);//0
int index2 = student1.IndexOf(new Student() { Id = 1, Name = "张三1" });//-1
int index3 = student1.FindIndex(stu => stu.Id == 2);
Console.WriteLine(index1); // 0
Console.WriteLine(index2); // -1
Console.WriteLine(index3); // 1
3.添加
student1.Add(new Student() { Id = 3, Name = "李四" });
student1.AddRange(
new Student[]
{
new Student(){ Id = 4, Name = "李四1"},
new Student(){ Id = 5, Name = "李四2"},
});
4.排序
student1.Sort(new ListCompare());
student1.ForEach(student =>
{
Console.WriteLine(student);
});
//编号:3,名称:李四
//编号:4,名称:李四1
//编号:5,名称:李四2
//编号:1,名称:张三1
//编号:2,名称:张三1
//编号:3,名称:张三2
5.以下是 List<T>
的一些关键特性和用法:
-
类型安全:
List<T>
是泛型集合,只能存储类型为T
的元素。这提供了编译时类型检查,避免了运行时的类型转换错误。 -
动态数组:
List<T>
可以根据需要自动调整其大小,就像ArrayList
一样。但是,由于类型安全,List<T>
提供了更好的性能。 -
快速索引访问:由于
List<T>
是基于数组实现的,它提供了快速的索引访问能力。 -
添加和删除元素:
List<T>
提供了Add
、AddRange
、Insert
、Remove
和RemoveAt
等方法来添加和删除元素。 -
查找元素:可以使用
IndexOf
、Contains
和Find
等方法来查找元素。 -
排序:
List<T>
提供了Sort
方法,可以对集合中的元素进行排序。也可以使用Sort
方法的重载版本,传入自定义的比较器。 -
反转:
List<T>
的Reverse
方法可以反转列表中元素的顺序。 -
复制:可以使用
CopyTo
方法将List<T>
中的元素复制到数组中。 -
容量和计数:
List<T>
有一个Capacity
属性,表示可以存储的最大元素数,以及一个Count
属性,表示当前存储的元素数。 -
枚举器:
List<T>
可以被foreach
循环直接遍历。 -
线程安全:
List<T>
不是线程安全的。如果需要在多线程环境中使用,可以使用List<T>
的线程安全版本,如ConcurrentBag<T>
或者使用锁来同步访问。
6.例子:
internal class Program
{
static void Main()
{
List<int> numbers = new List<int>();
// 添加元素
numbers.Add(10);
numbers.Add(20);
numbers.Add(30);
// 访问元素
Console.WriteLine(numbers[1]); // 输出 20
// 删除元素
numbers.Remove(20);
// 显示元素
foreach (var number in numbers)
{
Console.WriteLine(number);
}
// 获取元素数量
Console.WriteLine("Count: " + numbers.Count);
// 获取最大容量
Console.WriteLine("Capacity: " + numbers.Capacity);
// 排序
numbers.Sort();
// 反转
numbers.Reverse();
}
}