.net框架为数据存储和检索提供了专门的类,数组即是其中的一类,而集合就是对于数组的增强。
C# 中,有三种集合类型:
- 标准
- 通用的
- 同时
标准集合继承System.Collections,他们不将元素存储为特定类型的对象,而都是向上转型为 object 类型的对象。 标准集合包括ArrayList
,Hashtable
,Queue
和Stack
。
并发集合:C#并发集合是一种特殊的数据结构,它包含可以同时由多个线程访问的元素。它们大多是线程安全的,因此可以放心使用不同的线程来访问它们。此外,它们也可以使用原子操作提供高性能,将运算推迟到另一个线程中,以避免阻塞主线程。当多个线程同时访问并发集合时,必须考虑到会发生读写冲突。例如,当一个线程试图写入数据时,它可能会影响另一个线程正在读取的数据。此外,如果你想保证多线程应用程序的正确性,就可以使用互斥量来锁定集合,这样它就可以避免在同一时间内有多个线程对集合进行访问。.ConcurrentBag<T>、ConcurrentDictionary<TKey,TValue>、ConcurrentQueue<T>和ConcurrentStack<T>等。它们都是在System.Threading.Collections命名空间中定义的。
…………
集合也可以分类为:泛型结合,非泛型集合。
非泛型集合类位于System.Collections命名空间中;泛型类位于System.Collections.Generic命名空间;分别继承 IEnumerable和IEnumerable<T>用来实现轮询功能;实现ICollection和ICollection<T>,在此 接口/泛型接口 有Count/属性CopyTo/Add/Clear/Remove等方法;继承 IList和IList<T>提供了集合的项列表,有IndexOf/Insert/RemoveAt等方法;实现ISet<T>,使集合具有Add()、Remove()、Contains()、Clear()等方法,它还提供了用于迭代集合元素的GetEnumerator()等方法。
ArrayLIst(非泛型集合) :实现了IList、ICollection和IEnumerable接口
Arraylist于普通数组不同的是,其声明时,可以不用指明Arraylist的长度,即动态数组,非泛型集合中的元素都会向上转型为Object 类型。因此会有封箱和拆箱的操作。
Arraylist 中常用的方法:
Add | 将对象添加到 ArrayList 的结尾处。 |
AddRange | 将 ICollection 的元素添加到 ArrayList 的末尾。 |
BinarySearch | 已重载。 使用对分检索算法在已排序的 ArrayList 或它的一部分中查找特定元素。 |
Clear | 从 ArrayList 中移除所有元素。 |
Contains | 确定某元素是否在 ArrayList 中。 |
CopyTo | 已重载。 将 ArrayList 或它的一部分复制到一维数组中。 |
IndexOf | 已重载。 返回 ArrayList 或它的一部分中某个值的第一个匹配项的从零开始的索引。 |
Insert | 将元素插入 ArrayList 的指定索引处。 可在任意位置插入。 |
InsertRange | 将集合中的某个元素插入 ArrayList 的指定索引处。 |
LastIndexOf | 已重载。 返回 ArrayList 或它的一部分中某个值的最后一个匹配项的从零开始的索引。 |
Remove | 从 ArrayList 中移除特定对象的第一个匹配项。 |
RemoveAt | 移除 ArrayList 的指定索引处的元素。 |
Reverse | 已重载。 将 ArrayList 或它的一部分中元素的顺序反转。 |
Sort | 已重载。 对 ArrayList 或它的一部分中的元素进行排序。 |
ToArray | 已重载。 将 ArrayList 的元素复制到新数组中。 |
例:
static void Main(string[] args)
{
ArrayList array = new ArrayList();
array.Add(1);
array.Add("hahaa");
foreach (var value in array)
{
Console.WriteLine("value is {0}", value);
}
Console.ReadLine();
}
结果:
List:
是可以通过索引访问的对象的强类型列表, 即,仅存放指定类型的数据,不存在转型操作,效率高。 (List<T>
实际上是ArrayList
的泛型版本)
方法、属性名 | 说明 |
Count | 用于获取数组中当前元素数量 |
Item() | 通过指定索引获取或设置元素 |
Add() | 在List尾部添加一个元素的方法 |
AddRange() | 在List尾部添加一组元素 |
Clear() | 在List内移除所有元素 |
Any() | 测试一个元素是否在List内 |
Contains() | 测试一个元素是否在List内 |
CopyTo() | 把一个List拷贝到一维数组内 |
Exists() | 测试一个元素是否在List内 |
Find() | 查找并返回List内的出现的第一个匹配元素 |
FindAll() | 查找并返回List内的所有匹配元素 |
Getrange() | 拷贝指定范围的元素到新的List内 |
IndexOf() | 查找并返回每一个匹配元素的索引 |
Insert() | 在List内插入一个元素 |
InsertRange() | 在List内插入一组元素 |
LastIndexOf() | 查找并返回最后一个匹配元素的索引 |
Remove() | 移除与指定元素匹配的第一个元素 |
RemoveAt() | 移除指定索引的元素 |
RemoveRange() | 移除指定范围的元素 |
Reverse() | 反转List内元素的顺序 |
Sort() | 对List内的元素进行排序 |
ToArray() | 把List内的元素拷贝到一个新的数组内 |
TrimToSize() | 将容量设置为List中元素的实际数目 |
static void Main(string[] args)
{
List<int> intList = new List<int>();
Console.WriteLine("intList 的默认容量为:{0}", intList.Count);
intList.Add(1);
intList.Add(2);
intList.Add(3);
foreach (var value in intList)
{
Console.Write("添加元素后list元素"+value + " ");
}
Console.WriteLine();
Console.WriteLine("intList 的当前容量为:{0}", intList.Count );
Console.ReadLine();
}
结果为:
List<T> 在添加和删除元素等,对 List进行元素的增删,拷贝,都是将原有的元素拷贝到一个新的内存空间。
对于Arraylist 和List<T> 的比较:
Arraylist 的优点在于可以存放不同数据类型的不定长数据,如果内部初始化数组的长度不足时,会自动扩容2 倍,Arraylist的缺点很明显,因为存储的数据都是object 类型,如果将值类型的数据进行存入取出就要有“装箱拆箱” 的操作,会有性能上的影响。
HashSet<T>(泛型集合)
System.Collections.Generic命名空间中包含一个新的集合类:HashSet<T>,包含不重复项的无序列表,它通过使用哈希码来提供更快的查找速度,以及更有效的内存利用。集合基于散列值,插入元素的操作非常快,不需要像List<T>类那样重排集合。它也可以使用差集、交集和并集构建集合。
HashSet<T>中常见的方法:
①Add(): 如果元素不在集合中,Add()方法将该元素添加到集合中,返回一个bool值,用于判断元素是否添加成功。
②Clear : 删除集合中的所有元素。
③ Remove() 删除元素中指定元素。
④RemoveWhere() : RemoveWhere()方法需要一个Predicate<T>委托作为参数。删除满足谓词条件的所有元素
⑤ ExceptWith():ExceptWith()方法把一个集合作为参数,从集中删除该集合中的所有元素
⑥UnionWith():把传送为参数的集合中的所有元素添加到集中
………………
键值对集合哈希表(Hashtable)
System.Collections命名空间提供的一个容器处理和表现类似key/value的键值对,key通常可用来快速查找,同时key是区分大小写,value用于存储对应于key的值。其中 key/value键值对均为Object类型。
什么情况使用哈希表(HashTable)
(1)某些数据会被高频率查询
(2)数据量大
(3)查询字段包含字符串类型
(4)数据类型不唯一
哈希表的基本使用:
1,需要引用命名空间
using System.Collections; using System.Collections.Generic;
2,哈希表的基本操作
方法名 描述
Add(key,value) 在哈希表中添加一个key/value键值对
Remove(key) 在哈希表中去除某个key/value键值对
Clear() 从哈希表中移除所有元素
Contains(key) 判断哈希表是否包含特定键key
Hashtable ht = new Hashtable(); //创建一个hashtable实例
ht.Add("E", "e");//添加key/键值对
ht.Add("A", "a");
ht.Add("C", "c");
ht.Add("B", "b");
string s = (string)ht["A"];
if (ht.Contains("E")) //判断哈希表是否包含特定键,其返回值为true或false
Console.WriteLine("the E key:exist");
ht.Remove("C");//移除一个key/键值对
Console.WriteLine(ht["A"]);//此处输出a
ht.Clear();//移除所有元素
Console.WriteLine(ht["A"]); //此处将不会有任何输出
Console.ReadLine();
3. 哈希表的遍历
static Hashtable newhashtable = new Hashtable();
static void Main(string[] args)
{
newhashtable.Add("first", "Beijing"); // 添加key /value 键值对
newhashtable.Add("second", "Shanghai");
newhashtable.Add("third", "Hangzhou");
newhashtable.Add("forth", "Nanjing");
//遍历方法一:遍历哈希表中的键
foreach (string key in newhashtable.Keys)
{
Console.WriteLine(newhashtable[key]);
}
Console.WriteLine("--------------------");
//遍历方法二:遍历哈希表中的值
foreach (string value in newhashtable.Values)
{
Console.WriteLine(value);
}
Console.WriteLine("--------------------");
//遍历方法三:遍历哈希表中的键值
foreach (DictionaryEntry de in newhashtable)
{
Console.WriteLine(de.Value);
}
Console.WriteLine("--------------------");
//遍历方法四:遍历哈希表中的键值
IDictionaryEnumerator myEnumerator = newhashtable.GetEnumerator();
while (myEnumerator.MoveNext())
{
Console.WriteLine(newhashtable[myEnumerator.Key]);
}
Console.ReadLine();
结果:
DictionaryEntry是C#中的一个数据结构,它允许你将键和值对应在一起。它有两个属性Key和Value。Hashtable 内的每一组对象就是一个DictionaryEntry,在一个Hashtable中,Key的值是不可以重复的,必须是唯一的,但Value的值可以是重复的,在查询时,Key担当索引的功能
Dictionary( TKey , TValue )泛型键值对集合
C# 的 Dictionary<Tkey,TValue> 通过类在内部维护两个数组来实现功能:一个 keys 数组容纳要从其映射的键,另一个 values 容纳映射到的值;在 Dictionary<Tkey,TValue> 集合中插入键 / 值对时,将自动记录哪个键和哪个值关联,从而允许开发人员快速和简单地获取具有指定键的值。
Dictionary<>包含的一些方法:
方法名 说明
Add(TKey, TValue) 将指定的键和值添加到字典中。如果已经存在键,则抛出异
TryAdd(TKey, TValue) 尝试将指定的键和值添加到字典中。如果字典中存在具有给定键的元素,则不会重写元素,也不会做任何操作,返回false,否则返回true。
Clear() 将所有键和值从Dictionary中移除。
ContainsKey(TKey) 确定是否Dictionary包含指定键。
ContainsValue(TValue) 确定是否Dictionary包含指定值。
EnsureCapacity(int) 确保字典可容纳指定数量的条目,而无需进一步扩展其后备存储器。返回当前Dictionary中的容量。
Remove(Tkey) 从Dictionary中移除所指定的键的值。
Remove(TKey, TValue) 从Dictionary中删除具有指定键的值,并将删除的键对应的值复制到Value参数。
例:
// Dictionary 用来存储 TKey-TValue 对
Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();
// 向 Dictionary 中添加指定的 key 和 value
dict.TryAdd(TKey, TValue);
// 检查指定的 key 是否存在于 Dictionary 中
if (dict.ContainsKey(TKey))
{
// 如果指定的键存在于 Dictionary 中,则将其删除
dict.Remove(TKey);
}
遍历Dictionary<TKey, TValue>
Dictionary<int, string> MyDh = new Dictionary<int, string>(); //实实例化一个Dictionary
MyDh.Add(1, "111");
MyDh.Add(2, "222");
MyDh.Add(3, "333");
MyDh.Add(4, "444");
Console.WriteLine("遍历 Key 结果:");
foreach (int Key in MyDh.Keys) //遍历Dictionary 的 Key
{
Console.WriteLine(Key);
}
Console.WriteLine("遍历 Value 结果:");
foreach (string value in MyDh.Values) //遍历Dictionary 的 value
{
Console.WriteLine(value);
}
Console.WriteLine("遍历 Key-Value 结果:");
foreach (KeyValuePair<int, string> item in MyDh) //遍历Dictionary 中的 Key-Value
{
Console.WriteLine(item.Key + "\t" + item.Value);
}
Console.ReadLine();
运行结果:
迭代器(foreach):
foreach迭代器将对象集合作为参数进行迭代。它从集合中的第一个元素开始,并将每个元素逐一访问并应用指定的操作,直到它检查到最后一个元素。默认取值按照下标升序进行取值。
工作过程:
yield关键字用于返回值为IEnumerable、IEnumerator、IEnumerable<T>、IEnumerator<T>函数中,它有两个使用方法,yield break和yield return。
返回值为IEnumerable、IEnumerator、IEnumerable<T>、IEnumerator<T>的函数会自动生成一个迭代器,每个yield语句都表示一次暂停或中断。
yield break用于中断当前迭代,此时,自动生成的迭代器的MoveNext()会返回false。
yield return用于暂停当前函数,并返回一个值,返回的值可以在迭代器中的Current属性中获取。
再次调用迭代器的MoveNext时,会自动从上一个yield return之后开始运行。
例:
static IEnumerable<int> GetFibonacci() //斐波那契数列生成器
{
var last = -1;
var current = 1;
for ( int n= 0;n<15;n++)
{
var temp = last;
last = current;
current += temp;
n += 1;
yield return current; //其返回类型为IEnumerable
}
}
static void Main(string[] args)
{
foreach (var n in GetFibonacci()) //将创建的迭代器,放到foreach中循环
{
Console.WriteLine(n);
}
Console.ReadLine();
}