深入探索C#集合操作与优化技巧

更新:11-17 民间故事 我要投稿 纠错 投诉

各位老铁们,大家好,今天由我来为大家分享深入探索C#集合操作与优化技巧,以及的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

//预定义类型单一数据

整数索引=0;

浮动货币=3.14f;

布尔启用=真;

Console.WriteLine($"{index} {money} {enable}");

//数组容器

int[] arr={ 1, 2, 4 };

for (int i=0; i arr.Length; i++)

{

Console.WriteLine($"{arr[i]}");

}数组的缺点是,使用数组管理数据时,需要提前知道数组长度。在实际开发中,对于大量的数据,往往无法提前知道元素的个数。

数组是一种非常有用的数据结构,但它们也有严重的局限性。

数组元素的数据类型必须相同。创建数组时必须知道元素的数量。对于应用程序来说,需要通过循环索引来访问元素。因此,数组并不是最方便使用的数据结构。 C#提供了集合,通过集合来管理数据会更加方便。

集合

C# 提供了一系列具有特殊功能的类。这些类可以存储任意类型的对象,且长度可变,统称为集合。在C#编程语言中,集合结构分为泛型集合和非泛型集合。

集合命名空间

使用System.Collections 的非泛型集合使用System.Collection.Generic 集合的泛型集合是以高度结构化的方式存储任意对象的类。与无法动态调整大小的数组相比,集合不仅可以随意调整大小,而且还提供了更高级的方法来存储或检索其中的对象。

集合可以将一组相似类型的对象组合在一起。NET Framework 引入了泛型集合或非强类型非泛型集合。使用它们时,必须确保元素的类型是集合所需的类型。NET Framework 的强类型集合能够自动执行元素类型验证。

常见集合

Array Array List List:List是一个相当于数组的集合类。动态数组ArrayList、List键值对集合哈希集合/哈希表Hashtable字典字典堆栈Stack、Stack,堆栈的特点是后进先出(LIFO,Last In First Out)。队列,Queue,队列的特点是先进先出(FIFO,First In First Out)。可排序键值对:其特点是插入和检索高效的有序键值对列表SortedList,无需哈希表集合。 SortedList的特点是占用内存少,并且可以通过索引来访问。 SortedDictionary的特点是占用内存较多,并且没有索引,但插入和删除元素比SortedList要快。集合:特点是无序、不重复。 HashSet 集合HashSet 类可以被视为没有值的Dictionary 集合,类似于List。NET4.0支持SortedSet,这是一个有序且不重复的集合。双向链表集合:LinkedList的特点是快速添加和删除

简单数组

数组是一种数据结构,可以包含多个相同类型的元素

数组声明

//声明一个包含整数元素的数组

int[] intArray;使用[] 声明数组是C# 中Array 类的一种表示。在幕后使用C# 语法将创建一个从抽象基类Array 派生的新类。 Array 类是一个抽象类,不能使用构造函数来创建数组。

数组初始化

声明数组后,必须为数组分配内存以保存数组的所有元素。数组是引用类型,必须在堆上分配内存。 intArray=新int[3];数组声明和初始化数组的声明和初始化

int[] intArray=新int[3];使用数组初始值设定项为数组元素赋值

int[] intArray=new int[3]{1, 2, 4};初始化数组时不需要指定数组大小,编译器会自动统计元素数量。

int[] intArray=new int[]{1, 2, 4}; C# 编译器中数组的简化形式

int[] intArray={1, 2, 4};数组元素访问

声明并初始化数组后,您可以使用索引器来访问数组元素。数组仅支持带有整数参数的索引器。索引器从0 开始递增。

int[] intArray={1, 2, 4};

int i1=intArray[0];

int i2=intArray[1];

int i3=intArray[2];如果使用了错误的索引值,即没有对应的元素,则会抛出IndexOutOfRangeException 类型的异常。

数组的Length 属性表示数组元素的数量。

for(int i=0; i 自定义类型数组

用户类

{

公共int 用户ID { 获取;放; }

公共字符串用户名{获取;放; }

公共覆盖字符串ToString()

{

return String.Format("UserID={0} UserName={1}", UserID, UserName);

}

}

//如果数组元素是引用类型,则必须为数组元素分配内存。

//如果使用数组中未分配的内存元素,则会抛出NullReferenceException。

用户[]用户1=新用户[2];

users1[0]=新用户{ UserID=1, UserName="Alice" };

users1[1]=新用户{ UserID=2, UserName="Ben" };

//对自定义类型使用数组初始值设定项

用户[] 用户2=

{

新用户{ UserID=1, UserName="超人" },

新用户{ UserID=2, UserName="蝙蝠侠" }

};由于C#中的数组Array长度固定,开发过程中不易扩展,于是ArrayList诞生了。

动态数组 ArrayList

动态数组可以看作是扩展了功能的数组,但它并不等同于数组。动态数组之所以得名,是因为元素的数量和数据类型没有限制。可见任何类型的数据都保存在动态数组中。

ArrayList 和Array 的区别

Array的大小是固定的,ArrayList的大小可以根据需要自动扩展。 Array的特点是类型统一、长度固定,而ArrayList是变长数组。 Array 一次只能获取或设置一个元素的值,而ArrayList 允许添加、插入和删除一系列元素。 Array的下限是可以自定义的,而ArrayList的下限总是不为0。Array有多个维度,ArrayList总是只有一维。 Array 位于System 命名空间中,ArrayList 位于System.Collections 命名空间中。 ArrayList 是一个非泛型列表,可以将任何对象类型视为元素。 ArrayList arrayList=new ArrayList();动态数组的共同属性

容量属性表示集合中可以容纳的元素数量。 Count 属性指示集合中存储的实际元素数。动态数组的常用方法。

添加ArrayList.AddArrayList.AddRangeArrayList.RemoveArrayList.RemoveAtArrayList.ClearArrayList.ContainsArrayList.ToArrayArrayList.SortArrayList.Reverse 元素

动态数组提供了两种添加元素的方法

ArrayList.Add 将给定值对象插入到动态数组ArrayList的末尾public virtual int Add(Object value)//数组列表集合

ArrayList arrayList=new ArrayList();

//将元素添加到集合中

arrayList.Add(true);

//Console.WriteLine("count={0}capacity={1}", arrayList.Count, arrayList.Capacity);//1 4

arrayList.Add(1);

//Console.WriteLine("count={0} 容量={1}", arrayList.Count, arrayList.Capacity);//2 4

arrayList.Add(3.14);

//Console.WriteLine("count={0}capacity={1}", arrayList.Count, arrayList.Capacity);//3 4

arrayList.Add("a");

//Console.WriteLine("count={0} 容量={1}", arrayList.Count, arrayList.Capacity);//4 4

arrayList.Add("你好");

//Console.WriteLine("count={0} 容量={1}", arrayList.Count, arrayList.Capacity);//5 8

arrayList.AddRange(new int[] { 1, 3, 5, 7, 9 });

//Console.WriteLine("count={0}capacity={1}", arrayList.Count, arrayList.Capacity);//10 16//插入元素

arrayList.Insert(0, "第一个");

arrayList.InsertRange(1, new string[] { "java", "c#", "c++", "c" });

//访问集合

var 最后=arrayList[arrayList.Count - 1];

//删除集合

//arrayList.RemoveAt(2);

arrayList.RemoveRange(0, 3);

//遍历集合

for(int i=0; iArrayList arlst=new ArrayList();

arlst.AddRange(new int[] { 1, 3, 5, 7, 9 });

for(int i=0; i删除动态数组元素

ArrayList.Clear 清除元素并从动态数组中删除所有元素。 arrayList.Clear();ArrayList.Remove 删除动态数组元素并从动态数组中删除特定对象的第一个匹配项。 //从指定的ArrayList中移除obj对象。如果obj 不存在,则不会抛出异常,动态数组保持不变。

公共虚拟无效删除(对象对象)ArrayList arrayList=new ArrayList();

数组列表.Add(99);

arrayList.Add("chowjun");

字符串名称=new string(new char[] { "c", "j" });

arrayList.Add(名称);

用户u1=new User() { UserID=1, UserName="alice" };

arrayList.Add(u1);

arrayList.Remove(u1);

Console.WriteLine(arrayList.Count);ArrayList.RemoveAt 删除指定元素,并根据索引值移除动态数组元素。 public virtual void RemoveAt(int index)ArrayList.IndexOf 查找动态数组元素ArrayList.LastIndexOfArrayList.Contains 判断某个元素是否在动态数组中//item 是需要确认的元素,该方法返回一个布尔值。

public virtual bool Contains(Object item) 数组逆序

#region 数组列表

ArrayList arrayList=new ArrayList(new int[] { 1,3,5,7,9});

//按照降序排列

arrayList.Sort();//默认排序为升序

arrayList.Reverse();//反转

for (int i=0; i arrayList.Count; i++)

{

Console.WriteLine(arrayList[i]);

}

#endregionInitializer

//集合类初始化器

ArrayList 数字=new ArrayList() { 1, 2, 3, 4, 5, 6, 7 };

Hashtable 使用=new Hashtable()

{

{"约翰", 20},

{"戴安娜",33},

{"詹姆斯",29},

{"弗朗西斯卡",15}

};示例:扑克牌

使用两位数数组保存卡对象//枚举。套装颜色:黑色,红色,梅子色,4种

枚举套装

{

俱乐部、

钻石,

心,

黑桃

}

//枚举13种卡点

枚举值

{

二,

三,

四、

五,

六,

七,

八,

九,

十,

杰克,

女王,

国王,

高手

}

班级卡

{

公共西装套装;

公共价值价值;

}

类包

{

//4种颜色

公共const int NumSuits=4;

//13个面值

公共const int CardsPerSuit=13;

//52张牌

//私有哈希表cardPack;

private Card[,] cardPack;//4x13=52

//随机发牌

私有随机randomCardSelector=new Random();

//////构造函数:初始化扑克数组

///公共包()

{

//生成扑克数组实例

this.cardPack=new Card[NumSuits, CardsPerSuit];

//将扑克牌数组中的每个实例实例化为扑克牌对象

for (西装套装=Suit.Clubs; 西装=Suit.Spades;suit++)

{

for (值value=Value.Two; value=Value.Ace; value++)

{

this.cardPack[(int)suit, (int)value]=new PlayingCard(suit, value);

}

}

}

//////许可程序

//////公共卡DealCardFromPack()

{

//随机生成一种颜色

西装套装=(Suit)randomCardSelector.Next(NumSuits);

//判断该随机花色的所有牌是否都已发完

while (this.IsSuitEmpty(suit))

{

//重新随机生成一套花色

套装=(Suit)randomCardSelector.Next(NumSuits);

}

//随机生成卡值

值value=(Value)randomCardSelector.Next(CardsPerSuit);

//随机生成一张数组中值不为空的扑克牌。

while(this.IsCardAlreadyDealt(套装, 值))

{

值=(Value)randomCardSelector.Next(CardsPerSuit);

}

//设置卡面

卡牌=this.cardPack[(int)suit, (int)value];

this.cardPack[(int)suit, (int)value]=null;

退卡;

}

//////判断是否为空卡

/////////private bool IsSuitEmpty(西装套装)

{

布尔结果=真;

//判断每张牌的花色为花色(2~A)。如果有一张卡不为空,则结果值为假,否则为真。

for(值值=Value.Two;值=Value.Ace;值++)

{

if(!IsCardAlreadyDealt(花色, 值))

{

结果=假;

休息;

}

}

返回结果;

}

//如果数组中的元素为null,则表示该卡已发卡。

private bool IsCardAlreadyDealt(西装套装, Value值)

{

return (this.cardPack[(int)suit, (int)value]==null);

}

}

类手

{

公共常量int HandSize=13;

//用于存储玩家获得的卡牌

//private Card[] cards=new Card[HandSize];

公共ArrayList 卡=new ArrayList();

私有int 玩卡计数=0;

//给玩家发牌

公共无效AddCardToHand(卡cardDealt)

{

//使用ArrayList方法

//if(this.playingCardCount=HandSize)

//{

//抛出new ArgumentException("卡片太多");

//}

//this.cards[this.playingCardCount]=cardDealt;

//this.playingCardCount++;

//使用哈希表方法

if(this.cards.Count=HandSize)

{

throw new ArgumentException("卡片太多");

}

this.cards.Add(cardDealt);

}

}使用Hashtable保存卡片//枚举颜色:黑色、红色、紫红色,4种

枚举套装

{

俱乐部、

钻石,

心,

黑桃

}

//枚举13种卡点

枚举值

{

二,

三,

四、

五,

六,

七,

八,

九,

十,

杰克,

女王,

国王,

高手

}

班级卡

{

公共西装西装;

公共价值价值;

公共卡(西装套装、超值值)

{

西装=西装;

价值=价值;

}

}

类包

{

//4种颜色

公共const int NumSuits=4;

//13个面值

公共const int CardsPerSuit=13;

//52张牌

私有哈希表卡包;

//随机发牌

私有随机randomCardSelector=new Random();

//////构造函数:初始化扑克数组

///公共包()

{

//保存52张卡

this.cardPack=new Hashtable();

//依次读取颜色

for (西装套装=Suit.Clubs; 西装=Suit.Spades;suit++)

{

//为每个花色生成

SortedList cardsInSuit=new SortedList();

for (值value=Value.Two; value=Value.Ace; value++)

{

cardsInSuit.Add(值, 新卡(花色, 值));

}

this.cardPack.Add(suit, cardsInSuit);

}

}

//////许可程序

//////公共卡DealCardFromPack()

{ //随机生成一种花色 Suit suit = (Suit)randomCardSelector.Next(NumSuits); //判断该随机花色是否全部发完牌 while (this.IsSuitEmpty(suit)) { //重新随机生成一个花色 suit = (Suit)randomCardSelector.Next(NumSuits); } //随机生成牌面值 Value value = (Value)randomCardSelector.Next(CardsPerSuit); //随机产生一张扑克牌,其在数组中的值不为空。 while (this.IsCardAlreadyDealt(suit, value)) { value = (Value)randomCardSelector.Next(CardsPerSuit); } //设置牌面 SortedList cardsInSuit = (SortedList)cardPack[suit]; Card card = (Card)cardsInSuit[value]; cardsInSuit.Remove(value); return card; } ////// 判断是否为空牌面 /////////private bool IsSuitEmpty(Suit suit) { bool result = true; //判断具有suit花色的每张牌(2~A),若有一张牌不是null的result值为false,否则为true。 for (Value value = Value.Two; value<= Value.Ace; value++) { if (!IsCardAlreadyDealt(suit, value)) { result = false; break; } } return result; } //判断数组中的元素为null则表示该牌已经发出 private bool IsCardAlreadyDealt(Suit suit, Value value) { SortedList cardsInSuit = (SortedList)cardPack[suit]; return !cardsInSuit.ContainsKey(value); } } class Hand { public const int HandSize = 13; //用来存储玩家手中得到的牌 //private Card[] cards = new Card[HandSize]; public ArrayList cards = new ArrayList(); private int playingCardCount = 0; //给玩家发牌 public void AddCardToHand(Card cardDealt) { //使用ArrayList方式 //if(this.playingCardCount >= HandSize) //{ // throw new ArgumentException("too many cards"); //} //this.cards[this.playingCardCount] = cardDealt; //this.playingCardCount++; //使用Hashtable方式 if(this.cards.Count >= HandSize) { throw new ArgumentException("too many cards"); } this.cards.Add(cardDealt); } }ArrayList的优点在于它是可变长数组,可将任意多的数据Add到ArrayList中,其内部维护的数组当长度不足时,会自动扩容为原来的两倍。 ArrayList的缺点是存入ArrayList中的数据都是Object类型的,如果将值类型进行存入取出操作,就会发生装箱拆箱操作(值类型与引用类型相互转换),而装箱拆箱耗时且影响程序性能的。所以在 .NET2.0 泛型出现后,就提供了List。也就是说,List实际上是ArrayList的泛型版本,由于List不再需要装箱拆箱,可直接存取。虽然List与ArrayList操作上是一致的,不过使用前需设置好类型,否则是不允许Add的。

泛型集合 List

从性能上来说,如果存取的数组仅有一种数据类型,那么List是最优选择。 List只能存储固定类型的对象的一种集合要使用List必须引入System.Collections.Generic命名空间List是一个C#内置的类List本质和数组是一样的List类的内部维护了一个数组List比数组灵活,List类封装了方便操作内部数组各种方法,可方便的对数据进行增加、删除、修改等操作。List的长度是可以动态改变的实例化List类型对象时时无需指定长度的创建泛型集合 # 引入命名空间 using System.Collections.Generic; # 实例化对象 Listlist = new List(); Listlist = new List();泛型声明如果存取的数组是一个变长且数据类型多样,那最佳的选择仍然是ArrayList。 泛型集合基本操作 增加数据 # 向集合中添加数据,数据会不断地添加到集合,形成一种类似于排队的效果。 集合名.Add(Value)使用默认的构造函数创建的空列表,元素添加到列表后,列表的容量会扩大为可接纳4个元素。如果添加到第5个元素,列表的大小就重新设置为包含8个元素。如果8个元素仍旧不够,列表的大小会重新设置为包含16个元素。每次都会将列表的容量重新设置为原来的2倍。 如果列表的容量改变了,整个集合就要重新分配到一个新的内存块中。在List泛型类的实现代码中,使用一个T类型的数组。通过重新分配内存,创建一个新数组,Array.Copy()方法将旧数组中的元素复制到新数组中。为节省时间,如果事先知道列表中元素的个数,就可以用构造函数定义其容量。 # 创建容量为10个元素的集合 ListintList = new List(10); # 将集合容量重新设置为20 intList.Capacity = 20; # 获取集合元素个数 Console.WriteLine($"Capactiy={intList.Capacity} Count={intList.Count}");如果已经将元素添加到列表中,且不希望添加更多的元素,可调用TrimExcess()方法,去除不需要的容量。但是,因为重新定位需要时间,所以如果元素个数超过了容量的90%,TrimExcess()方法就说明也不做。 intList.TrimExcess();List泛型集合类的实现代码中,使用了一个T类型的数组。通过重新分配内存,创建了一个新数组, 批量添加 使用List类的AddRange()方法可一次给集合添加多个元素,因为AddRange()方法的参数是IEnumerable类型的对象,所以可以传递一个数组。 查询数据 # 获取指定索引位置的数据 集合名[索引值]List的索引和数组一样,都是从0开始。List的长度通过集合名.Count属性获取Capacity属性可获取和设置集合的容量,集合容量与集合元素个数不同,集合元素个数使用Count属性读取,集合容量总是大于或等于元素个数。只要不将元素添加到列表中,元素个数就为0。 //实例化泛型集合 ListintList = new List(); //增加元素 intList.Add(1); intList.Add(2); intList.Add(4); //集合容量与大小 Console.WriteLine($"Capacity={intList.Capacity} Count={intList.Count}");//4 3管理对象 定义对象类class User { public int UserID; public string UserName; public User(int userid, string username) { this.UserID = userid; this.UserName = username; } public override string ToString() { return string.Format($"UserID={UserID} UserName={UserName}"); } }实例化对象并添加到集合//定义数据 Listusers = new List(); //实例化对象

User u1 = new User(1, "alice"); User u2 = new User(2, "ben"); User u3 = new User(3, "carl"); //添加对象到集合 users.Add(u1); users.Add(u2); users.Add(u3);//添加对象到集合 users.Add(new User(4, "elva")); users.Add(new User(5, "fifi")); users.Add(new User(6, "gaga"));使用List类的AddRange()方法,可一次性给集合添加多个元素,因为AddRange()的参数是IEnumerable类型的对象,所以可传递一个数组。 users.AddRange(new User[] { new User(7, "han"), new User(8, "irk"), new User(9, "lala") });如果在实例化列表时知道集合元素个数,可将实现IEnumerable类型的任意对象传递给类的构造函数,类似AddRange()方法。 Listuserlist = new List(new User[] { new User(1, "alice"), new User(2, "ben"), new User(3, "carl") });插入元素使用Insert()方法可在位置插入元素 userlist.Insert(0, new User(4, "elva"));使用InsertRange()方法可批量插入多个元素,类似AddRange()方法。 userlist.InsertRange(1,new User[] { new User(5,"fifi"), new User(6,"gaga"), });如果索引集大于集合中的元素个数,则会抛出ArgumentOutOfRangeException类型的异常。 4.访问元素 实现了IList和IList接口的所有类都提供了一个索引器,可使用索引器,通过传递元素索引号来访问元素。第一个元素可使用索引值为0来访问。 Console.WriteLine(userlist[0]);从集合中删除指定数据指定索引删除元素 users.RemoveAt(0);按索引删除比较快,因为必须在集合中搜索要删除的元素。Remove()方法先在集合中搜索,使用IndexOf()方法获取元素的索引,再使用该索引删除元素。IndexOf()方法会先检查元素类型是否实现了IEquatable接口。如果实现了,则调用接口的Equals()方法,确定集合中的元素是否等于传递给Equals()方法的元素。如果没有实现这个接口,则使用Object类的Equals()方法比较这些元素。Object类中的Equals()方法默认实现代码对值类型进行按位比较,对引用类型仅比较其引用。 指定元素删除 //删除元素 users.Remove(u1);4.修改集合中指定数据 5.查询搜索显示集合中的数据 有不同的方式在集合中搜索元素,可获得要查找元素的索引,或搜索元素本身。 List.IndexOf() IndexOf()方法需要将一个对象作为参数,若在集合中找到该元素,方法返回该元素的索引。若没有找到元素则返回-1。IndexOf()方法使用IEquatable接口来比较元素。//定义数据 Listusers = new List(); //实例化对象 User u1 = new User(1, "alice"); User u2 = new User(2, "ben"); User u3 = new User(3, "carl"); //添加对象到集合 users.Add(u1); users.Add(u2); users.Add(u3); //删除元素 users.Remove(u1); //查询元素 Console.WriteLine(users.IndexOf(u1));//-1 Console.WriteLine(users.IndexOf(u2));//0 Console.WriteLine(users.IndexOf(u3));//1List.LastIndexOf()List.FindIndex()List.FindLastIndex()List.Find()User user = users.Find(x=>x.UserName == "alice");List.FindLast()若只检查元素是否存在,List仅仅提供了Exists()方法。 综合案例:用户管理 (1)创建用户实体类UserEntity using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace UserManage { ////// 用户实体类 ///public class UserEntity { public int UserID { get; set; } public string UserName { get; set; } public string Phone { get; set; } public string Email { get; set; } public UserEntity(string username, string phone, string email) { this.UserID = new Random().Next(10000000, 99999999); this.UserName = username; this.Phone = phone; this.Email = email; } public override string ToString() { return string.Format("{0,-10}t{1,-10}t{2,-11}t{3,-20}", UserID, UserName, Phone, Email); } } }(2)创建用户控制器UserController using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace UserManage { ////// 用户控制器 ///public class UserController { Listuserlist = new List(); public void Read() { if(userlist.Count == 0) { Console.WriteLine("Message: no data..."); } foreach(UserEntity item in userlist) { Console.WriteLine(item); } } public void Create(UserEntity item) { userlist.Add(item); } public void Delete(string key, string val) { if(key.ToLower() == "userid") { int userid = Convert.ToInt32(val); RemoveByUserID(userid); } else if(key.ToLower() == "phone") { RemoveByUserPhone(val); } } public void RemoveByUserID(int userid) { UserEntity user = userlist.Find(x =>x.UserID == userid); if (user == null) { Console.WriteLine("Message: user does not exists..."); } userlist.Remove(user); } public void RemoveByUserPhone(string phone) { UserEntity user = userlist.Find(x =>x.Phone == phone); if (user == null) { Console.WriteLine("Message: user does not exists..."); } userlist.Remove(user); } } }(3)创建用户视图UserView using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace UserManage { class UserView { public static void Main(string[] args) { //实例化控制器程序 UserController userController = new UserController(); //接收用户输入 while (true) { string cmd = string.Empty; Console.WriteLine("Please Input Option: [0]EXIT [1]CREATE [2]UPDATE [3]READ [4]DELETE [5]SEARCH"); Console.Write("Option: "); cmd = Console.ReadLine(); switch (cmd) { case "0": Process.GetCurrentProcess().Kill(); break; case "1": //接收数据 Console.Write("UserName: "); string username = Console.ReadLine(); Console.Write("Phone: "); string phone = Console.ReadLine(); Console.Write("Email: "); string email = Console.ReadLine(); //增加数据 userController.Create(new UserEntity(username, phone, email)); break; case "2": break; case "3": userController.Read(); break; case "4": Console.WriteLine("Please Input Delete Option: [1]UserID [2]Phone"); Console.Write("Option: "); string command = Console.ReadLine(); if(command == "1") { Console.Write("UserID:"); string input = Console.ReadLine(); int userid = 0; if (!int.TryParse(input, out userid)) { Console.WriteLine("Error: username must be numberic"); } else { userController.RemoveByUserID(userid); } } else if(command == "2") { Console.Write("Phone:"); string input = Console.ReadLine(); long output = 0; if (!long.TryParse(input, out output)) { Console.WriteLine("Error: phone must be numberic"); } else { userController.RemoveByUserPhone(output.ToString()); } } else { Console.WriteLine("Please input delete option..."); } break; default: Console.WriteLine("Please Input Option Number");break; } Console.WriteLine("====================================================================="); } } } }

哈希表 Hashtable

Hashtable称为哈希表,表示键值对的集合,其键值对根据键的哈希代码进行组织,哈希表的每个元素都是存储在DictionaryEntry对象中的键值对。 哈希表是键值对的集合,类似于字典。哈希表在查找元素时速度很快哈希表的键值对集合中的键绝对不能重复哈希表的键不能为空引用,值可以。哈希表的构造函数 使用默认的初始容量、加载因子、哈希代码提供程序和比较器进行初始化Hashtable类的新的空实例。public Hashtable()使用指定的初始容量、默认加载因子、默认哈希代码提供程序和默认比较器来初始化Hashtable类的新的空实例。public Hashtable(int capacity) # capacity 表示Hashtable对象最初可以包含的元素的近似数量哈希表的属性 Hashtable.Count 获取包含在Hashtable中的键值对的数目 Hashtable.IsFixedSize 获取一个值,该值指示哈希表是否具有固定大小。 Hashtable.IsReadOnly 获取一个值,该值指示哈希表是否为只读。 Hashtable.IsSynchronized 获取一个值,该值只是是否同步对哈希表的访问。 Hashtable.Item 获取或设置与指定的键相关联的值 Hashtable.Keys 获取包含哈希表中的键的ICollection Hashtable.SyncRoot 获取可用于同步哈希表访问的对象 Hashtable.Values 获取包含哈希表中的值的ICollection哈希表添加元素 # 将带有指定键和值的元素添加到哈希表中 public virtual void Add(Object key, Object value) # key 表示要添加元素的键名 # value 表示要添加元素的键值,可为空引用。若哈希表指定了初始容量,则不用限定向哈希表对象中添加的因子个数,其容量会根据加载的因子自动增加。 Hashtable ht = new Hashtable(); ht.Add("UserID", 1); ht.Add("UserNO", "BH0001"); ht.Add("UserName", "Tim"); ht.Add("UserGender", 1); int count = ht.Count; Console.WriteLine(count); //4哈希表元素的删除 # 从哈希表中移除所有元素 public virtual void Clear() # 从哈希表中移除带有指定键的元素 public virtual void Remove(Object key)Hashtable ht = new Hashtable(); ht.Add("UserID", 1); ht.Add("UserNO", "BH0001"); ht.Add("UserName", "Tim"); ht.Add("UserGender", 1); Console.WriteLine(ht.Count); //4 ht.Remove("UserGender"); Console.WriteLine(ht.Count); //3 ht.Clear(); Console.WriteLine(ht.Count); //0哈希表的遍历 哈希表的遍历使用foreach,由于哈希表中的元素是键值对,因此需要使用DictionaryEntry类型来进行遍历。DictionaryEntry类型表示一个键值对的集合。 Hashtable ht = new Hashtable(); ht.Add("UserID", 1); ht.Add("UserNO", "BH0001"); ht.Add("UserName", "Tim"); ht.Add("UserGender", 1); foreach(DictionaryEntry dic in ht) { Console.WriteLine($"{dic.Key} = {dic.Value}"); }哈希表元素的查找 # 确定哈希表中是否包含特定的键 public virtual bool Contains(Object key) # key 表示要在哈希表中定位的键 # return 若哈希表中包含具有指定键的元素则返回true,否则返回false。

字典 Dictionary

字典表示一种复杂的数据类型,其数据结构允许按照某个键来访问元素,因此也被称为映射或散列表。 字典的主要特征是能够根据键快速查找值,也可以自由添加和删除元素,类似List,但没有在内存中移动后续元素的性能开销。 将键添加到字典后,键会转换为一个散列,利用散列创建一个数字,它将索引和值关联起来。然后索引包含了一个到值得链接。因为一个索引项可以关联多个值,索引可存储为一个树形结构。 Dictionary集合是一种键值对集合,该集合中的每个数据都由两部分组成:键和值。其中键必须唯一,而值可以有重复。通过键去寻找值,这一点和List不同。在List泛型集合中,只限定了数据T的类型,而在Dictionary泛型集合中,需要分别限定键K和值V的类型。 Dictionary<[key], [value]>当大量使用key来查找value的时候,Hashtable无疑是最佳选择。由于Hashtable和ArrayList一样都是非泛型的,存入的value均是object类型,因此存储时都会发生装箱拆箱操作,进而影响程序性能。因此,出现了Dictonary,也就是说Dictionary实际上就是Hashtable的泛型版本。Dictonary不仅存取快速而且无需装箱拆箱,同时它优化了算法,其Hashtable是0.72,从而减少了容量的浪费。 Dictionarydict = new Dictionary();字典Dictonary同样也是用来表示键值对的集合,由于它是一个泛型,本身又具有集合的功能,因此可见其视为数组。 键的类型 用作字典中的键必须重写Object类的GetHashCode()方法,只要字典类需要确定元素的位置,就要调用GetHashCode()方法,并返回int由字典用于计算在对应位置放置元素的索引。它涉及素数,所以字典的容量是一个素数。因此,字典的性能取决于GetHashCode()方法的实现代码。 GetHashCode()方法实现代码必要条件 相同的对象总是返回相同的值,不同的对象可以返回相同的值。执行比较快,计算的开销不大。不能抛出异常至少使用一个实例字段散列代码应平均分布在int可以存储的整个数字范围上散列代码最好在对象的生存期中不发生变化Hashtable与Dictionary异同点 在单线程程序中推荐使用Dictionary,由于具有泛型优势且读取速度较快,其容量利用会更加充分。在多线程程序中推荐使用Hashtable,默认的Hashtable允许单线程写入多线程读取,对Hashtable进一步调用Synchronized()方法可获得完全线程安全的类型。而Dictionary是非线程安全的,必须人为使用lock语句进行保护,其效率大减。经过测试发现,但key是整型时Dictionary的操作效率要高于Hashtable,而当key是字符串时则Dictionary的效率并没有Hashtable的快。Dictionary有按插入顺序排列数据的特性,但是当调用Remove()方法删除节点后原来的顺序会被打乱掉。因此在需要体现顺序的场景中使用Dictionary能获得一定的便利。遍历Dictionary时会采用插入时的顺序,而遍历Hashtable则是打乱掉的。泛型Dictionary基本使用 创建字典泛型集合 引入命名空间using System.Collections.Generic实例化对象Dictionary集合名称 = new Dictionary();using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace TestApp { class Program { /*统计文本中的单词数量*/ static DictionaryCountWords(string text) { var frequencies = new Dictionary(); string[] words = Regex.Split(text, @"W+"); foreach(string word in words) { if (frequencies.ContainsKey(word)) { frequencies[word]++; } else { frequencies[word] = 1; } } return frequencies; } static void Main(string[] args) { string text = @"Do you like green eggs and ham? I do not like them, Sam-I-am. I do not like green eggs and ham."; Dictionaryfrequencies = CountWords(text); foreach(KeyValuePairentry in frequencies) { string word = entry.Key; int frequency = entry.Value; Console.WriteLine("{0} {1}", word, frequency); } Console.ReadKey(); } } }字典数据操作 字典增加数据 # 向字典中添加数据 Dictionary.Add(K, V)字典的键是唯一的,不能添加两个相同键名的数据。 查询字典数据 # 获取指定键名所对应的键值 字典泛型集合名[键名]字典泛型集合的长度可通过字典泛型集合名称.Count属性获取 删除数据 # 删除指定键名所对应的数据 字典泛型集合名.Remove(键名);修改数据 # 给制定键名所对应的数据重新赋值 字典泛型集合名[键名]=新值;遍历字典集合 # 实例化字典泛型集合 Dictionarydic = new Dictionary(); dic.Add("Name", "chowjun"); dic.Add("Email", "chowjun520@hotmail.com"); # 不能添加相同键名的数据 //dic.Add("Name", "junchow"); # 修改键名所对应的数据 dic["Name"] = "junchow"; # 删除指定键名所对应的数据 dic.Remove("Email"); # 获取键名对应的数据 Console.WriteLine(dic["Name"]);//junchow # 获取字典的元素个数 Console.WriteLine(dic.Count);//1 # 获取所有键名 //dic.Keys; #遍历字典集合 foreach(var item in dic.Keys) { Console.WriteLine($"Key={item}tValue={dic[item]}"); }# 实例化字典泛型集合 Dictionarydic = new Dictionary(); # 添加 Guid guid = Guid.NewGuid(); dic.Add(guid, new Random().Next(100000,999999)); # 修改 dic[guid] = new Random().Next(100000, 999999); # 遍历 foreach(KeyValuePairitem in dic) { Console.WriteLine($"TKey={item.Key}tTValue={item.Value}"); }字典泛型集合应用场景 凡是键值对结构的数据都可以使用Dictionary

关于深入探索C#集合操作与优化技巧到此分享完毕,希望能帮助到您。

用户评论

抓不住i

C# 集合真好用,很多场景都能用到.

    有19位网友表示赞同!

伱德柔情是我的痛。

想学习C# 一定要去了解集合啊!

    有9位网友表示赞同!

你身上有刺,别扎我

这些集合类感觉设计得很巧妙,实用性强。

    有18位网友表示赞同!

像从了良

以前写C# 代码的时候没怎么用过集合,现在看来确实很方便。

    有17位网友表示赞同!

雪花ミ飞舞

看了下C# 的不同集合类型,真是眼花缭乱。

    有17位网友表示赞同!

玩味

C# 集合学习起来挺有趣的!

    有11位网友表示赞同!

关于道别

哪个场景适合使用哪种集合? 这太难抉择了.

    有18位网友表示赞同!

青楼买醉

感觉掌握 C# 集合,写程序的速度能提高不少。

    有19位网友表示赞同!

漫长の人生

以后面试的时候应该要记得多问一些关于集合的问题.

    有19位网友表示赞同!

采姑娘的小蘑菇

C# 集合的使用技巧好多,还得慢慢积累经验。

    有8位网友表示赞同!

你的眸中有星辰

学习完 C# 的集合感觉代码更加美观了

    有14位网友表示赞同!

花海

希望可以找到更多 C# 集合的使用案例来参考。

    有12位网友表示赞同!

凉城°

使用 C# 集合效率比其他的方法高不少呢!

    有16位网友表示赞同!

苏樱凉

C# 集合真是一门好学又实用的知识!

    有17位网友表示赞同!

七夏i

现在很多项目用到数据结构,集合必不可少啊!

    有13位网友表示赞同!

优雅的叶子

这个主题贴太棒了!正好可以用来看一看 C# 集合的学习资料。

    有12位网友表示赞同!

安之若素

C# 集合和数据库结合起来使用感觉很强大!

    有11位网友表示赞同!

孤自凉丶

以后用 C# 做游戏,应该会用到集合吧?

    有17位网友表示赞同!

红尘滚滚

还在纠结哪个版本 C# 的集合函数更好用,需要好好研究一下.

    有6位网友表示赞同!

【深入探索C#集合操作与优化技巧】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活

上一篇:2024年免费手游平台推荐及排行榜:精选平台,畅享免费游戏体验 下一篇:深入解析:RabbitMQ中的队列与交换机差异对比