C#之再议数组和集合


1.数组

  1.1简单数组

  1.2 多维数组

  1.3锯齿数组

  1.4Array数组

  1.5作为参数的数组

  1.6枚举

  1.7结构

    以上部分可参考 http://www.cnblogs.com/ztb123/articles/4195864.html

  1.8元组

    数组合并了相同类型的对象,而元组合并了不同类型的对象.Net 4定义了 8个泛型 Tuple类 和一个静态 Tuple类 ,它们用作元组的工厂。 这里的不同泛型 Tuple类支持不同数量的元素。 例如,Tuple<T1> 包含-个元素,Ttple<T1,T2> 包含两个元素,以此类推,元组用Tuple的静态Create()方法创建。

1   public static Tuple<int, int> Divide(int dividend, int divisor)
2         {
3             int result = dividend / divisor;
4             int reminder = dividend % divisor;
5             return Tuple.Create(result, reminder);
6         }
7
8             var result = Divide(2,3);
9             Console.WriteLine("result if division:{0},reminder:{1}", result.Item1, result.Item2);

Demo

如果元组包含的项超过 8个,就可 以使用 带 8个参数的 Tuple类 定义。 最后一个模板参数是 TRrest,表示必须给它传递一个元组。 这样,就可以创建带任意个参数的元组了,可在类上右键转到定义查看。

2集合

  2.1集合和接口类型

  大多数集合类都可在 systm.Collections和 system.Collections.Generic名称空间中找到 。 泛型集合 类 位 于System.Collections.Generic名 称 空 间 中,专门于特定类型的集合类位于System.Collections.Specialized名称空间中,线程安全的集合位于System.Collections.Concurrent名称空间中。

  集合和列表实现的接口:  

  • IEnumerable<T>  如果将Foreache语句用于集合,就需要IEnumerable接口,这个接口定义了GetEnumerator()方法,它返回一个实现了IEnumable接口的枚举。
  • ICollection<T> 这个接口由泛型集合类实现。使用这个接口可以获得集合中的元素个数(Count属性),把集合复制到数组中(CopyTo()方法),还可以从集合中添加和删除元素(Add(),Remove(),Clear())
  • IList<T> 此接口用于 可通过位置访问其中的元素的列表,这个接口定义了一个索引器,可以在集合的指定位置插入或删除某些项,此接口派生自ICollection<T>接口
  • ISet<T> 实现这个接口的集合可以允许合并不同的集,获得2个集合的交集,检查2个集合是否重叠,此接口派生自ICollection<T>接口
  • IDictionary<TKey,TValue> 此接口有包含键和值的泛型集合实现,使用这个接口可以访问所有的键和值,使用键类型的索引可以访问某些项,还可以添加和删除某些项。
  • ILookup<TKey,TValue> 此接口类似于IDictionary<TKey,TValue>接口,实现此接口的集合有键和值,且可以通过一个键包含多个值。
  • IComparer<T> 此接口由比较器实现,通过compare()方法给集合中的元素排序
  • IEquaityComparer<T>此接口由一个比较器实现,发、该比较器可以用于字典中的键。使用这个接口可以对对象进行相等性比较。
  • IProducerConsumerCollection<T>此接口支持新的线程安全的集合类

  2.2列表

  .Net Framework为动态列表提供了泛型类List<T>.这个类实现了IList,IConllection,IEnumerable IList<T>,ICollection<T>和IEnunerable<T>接口。

  使用默认的构造函数创建一个空列表,元素添加到列表后,列表的容量就会扩大为可接纳4个元素,如果添加了第5个元素,列表的大小就会变为原来的2倍,以此类推。如果列表的容量改变了,整个集合就会重新分配到一个新的内存中,所以为了节省时间,如果事先知道列表的容量,就可以用构造函数定义其容量。

   List<int> list = new List<int>() { 1, 2 };
            list.Add(3);//添加
            list.Insert(0, 4);//插入
            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine(list[i]);//访问元素
            }
            list.RemoveAt(3);//删除
            int num=  list.IndexOf(2);//查找
            list.Sort();//排序
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
            list.AsReadOnly();//设置为只读集合,所有的修改集合的方法和属性都会抛出NotSupportedExection异常

List

  2.3队列

  队列是其元素 以先进先出的 方式来处理的集合。使用泛型类Queue<T>实现

  Queue<T>类的方法:

  • Count 返回队列中的元素个数
  • Enqueue()在队列的一段添加一个元素
  • Dequeue()在队列的头部读取和删除一个元素。如果队列中没有元素会抛出一个InvalidOperationException类型的异常。
  • Peek() 从队列的头部读取一个元素,但不会删除它
  • TrimExcess() 重新设置队列的容量,Dequeue()方法从队列中删除元素,但不会重新设置队列的容量,要从队列的头部去除空元素,应使用此方法。

  2.4栈

   栈是与队列非常相似的一个容器,但它是先进后出。

  

  Statck<T>类的成员:

  • Count 返回栈中的元素个数
  • Push() 在栈顶部添加一个元素
  • Pop()从栈顶部移除一个元素,并返回该元素。如果栈是空的,就会抛出一个InvalidOPerationExcepron异常
  • Peek() 返回栈顶部的元素,但不删除
  • Contains() 确定某个元素是否在栈中,如果是返回true

  2.5链表

  LinkList<T>是一个双向链表,其元素指向它前面和后面的元素。链表的优点是,如果将元素插入到列表的中间位置,使用链表会非常快,在插入一个元素时,只需修改上一个元素的 Next引 用和下一个元素的Previous引用 ,使 它们引用所插入的元素。缺点是链表元素只能一个接一个的访问。

  2.6有序列表

  如果需要基于键对所需集合排序,就可 以使用 SoftedList<TKey,TValue>类。这个类按照键给元素排序。 集合中的键和值都可以使用任意类型。

 1 var books = new SortedList<string, string>();
 2             books.Add("C# 2012 wrox box","978-987-9989-7");
 3             books.Add("Professional", "978-987-9989-9");
 4             books["Beginning Visual C# 2008"] = "978-987-9989-8";
 5             books["C# 2008"] = "978-987-9989-5";
 6
 7             foreach (KeyValuePair<string,string> book in books)
 8             {
 9                 Console.WriteLine("{0},{1}",book.Key,book.Value);
10             }

SoftList

  输出默认按键的顺序输出。

  2.7字典

  字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素字典也称为映射或散列表。字典的主要特性是能根据键快速查找值 。也可以自由添加和删除元素,但 没有在 内存中移动后续元素的性能开销。

 1 Dictionary<int, int> dic = new Dictionary<int, int>();
 2             dic.Add(1, 1);
 3             dic[2] = 2;
 4             dic[3] = 3;
 5             dic.Add(4,4);
 6             dic.Remove(2);
 7             foreach (var item in dic)
 8             {
 9                 Console.WriteLine("key:{0},Value:{1}",item.Key,item.Value);
10             }

Dictionary

2.7.1 有序字典

  SortedDictionary<TKey,TValue>类是一个二叉搜索树,其中的元素根据键来排序。
  • SortedList<TKey,TValue>类使用的内存比SortedDictionay<TKey,TValue>类少
  • SortedDictionay<TKey,TValue>类的元素的插入和删除速度比较快
  • 在用 已排好序的数据填充集合时,若 不需要修改容量,SortedList<TKey,TValue> 比较决

   2.8 集合

  包含不重复元素的集合称为"集" 。 .NET4包 含两个集(HashSet<T>(无序)和SortedList<T>(有序))。

 1  var set1 = new HashSet<int>() { 1, 2, 3, 4, 5 };
 2             var set2 = new HashSet<int>() { 4, 5, 6, 7, 8 };
 3             set1.ExceptWith(set2);
 4             foreach (var item in set1)
 5             {
 6                 Console.WriteLine(item);
 7             }
 8
 9
10             set1.UnionWith(set2);
11
12             foreach (var item in set1)
13             {
14                 Console.WriteLine(item);
15             }

HashSet

2.9可观察的集合

  如果需要集合中的元素何时删除或添加的信息,就可以使用ObservableCollection<T>类,这个类是为WPF定义的,这样UI就可以知道集合的变化。这个类需要映入程序集WindowBase,

 1  var date =new  ObservableCollection<string>();
 2             date.CollectionChanged += Date_CollectionChanged;
 3             date.Add("1");
 4             date.Insert(0, "2");
 5             date.Remove("1");
 6             Console.ReadKey();
 7  private static void Date_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
 8         {
 9             Console.WriteLine("action{0}",e.Action.ToString());
10             if (e.OldItems != null)
11             {
12                 Console.WriteLine("starting index for old item(s):{0}",e.OldStartingIndex);
13                 Console.WriteLine("OldItem(s):");
14                 foreach (var item in e.OldItems)
15                 {
16                     Console.WriteLine(item);
17                 }
18             }
19             if (e.NewItems != null)
20             {
21                 Console.WriteLine("starting index for new item(s):{0}", e.NewStartingIndex);
22                 Console.WriteLine("NewItem(s):");
23                 foreach (var item in e.NewItems)
24                 {
25                     Console.WriteLine(item);
26                 }
27             }
28             Console.WriteLine();
29         }

ObservableCollection

  2.10并发集合

  为了对集合进行线程安全的访问,定义了IProducerConsumerCollection<T>接口,这个接口重要的方法是TryAdd() (尝试给集合添加一项,如果集合禁止添加,这个操作就可能失败,返回一个Bool值)和TryTake()(工作方式和TryAdd相同,以通知调用者操作是成功还是失败,并在操作成功后返回集合中的项).

  • ConcurrentQueue<T>  这个集合类用 一种免锁定的算法实现,使用在 内部合并到一个链表中的 32项数组.访 问队列元素的方法有 Enqueue()、 TryDequeue()和 TryPeek()。 这些方法的命名非常类似Queue<T>累的方法,只是个可能调用失败的方法前边加了Try.因为这个类实现了IProducerConsumerCollection<T>接口,所以TryAdd()和TryTake()方法值调用Enqueue()和TryDequeue()方法。
  • ConurrentStack<T> 类似于ConcurrentQueue<T> 只 是带有另外的元素访 问方法。此类定义了Push().PushRange().TryPeek().TryPop()和TryPopRange()方法。
  • ConcurrentDictionary<TKey,TValue> 这是一个线程安全的键值集合。TryAdd().TryGetValue().TryRemove()和TryUpdate()方法以非阻塞的方式访问成员,因为元素基于键和值,所以此类没有实现IProducerConsumerCollection<T>接口。
  • BlockingCollection<T> 这个集合在可以添加和删除之前会阻塞线程并一直等待。它提供了一个接口,以使用Add()和Take()方法来添加和删除元素。

 1  var sharedCollection = new BlockingCollection<int>();
 2             var events = new ManualResetEventSlim[2];
 3             var waits = new WaitHandle[2];
 4             for (int i = 0; i < 2; i++)
 5             {
 6                 events[i] = new ManualResetEventSlim(false);
 7                 waits[i] = events[i].WaitHandle;
 8             }
 9
10             var producer = new Thread(obj=> { var state = (Tuple<BlockingCollection<int>,ManualResetEventSlim>)obj;
11                 var coll = state.Item1;
12                 var ev = state.Item2;
13                 var r = new Random();
14                 for (int i = 0; i < 300; i++)
15                 {
16                     coll.Add(r.Next(3000));
17                     ev.Set();
18                 }
19             });
20
21             producer.Start(Tuple.Create<BlockingCollection<int>, ManualResetEventSlim>(sharedCollection, events[0]));
22
23             var consumer = new Thread(obj=> {
24             var state = (Tuple<BlockingCollection<int>, ManualResetEventSlim>)obj;
25             var coll = state.Item1;
26             var ev = state.Item2;
27
28                 for (int i = 0; i < 300; i++)
29                 {
30                     int result = coll.Take();
31                 }
32                 ev.Set();
33             });
34
35             consumer.Start(Tuple.Create<BlockingCollection<int>,ManualResetEventSlim>(sharedCollection,events[1]));
36
37             if (!WaitHandle.WaitAll(waits))
38                 Console.WriteLine("wait failed");
39             else
40                 Console.WriteLine("reading/writing finished");
41
42             Console.ReadKey();

BlockingCollection

 

时间: 2024-10-10 15:38:41

C#之再议数组和集合的相关文章

.NET 基础 一步步 一幕幕[数组、集合、异常捕获]

数组.集合.异常捕获 数组: 一次性存储多个相同类型的变量. 一维数组: 语法: 数组类型[] 数组名=new 数组类型[数组长度]; 声明数组的语法: A.数据类型 [] 数组名称= new 数据类型[2]{1,2}: B.数据类型 [] 数组名称 = new 数据类型[数组大小]; C. 数据类型 [] 数组名称 = {数据,数据,数据,数据}; ***数组的长度一旦固定了,就不能再被改变了 可以通过索引来访问数组中的元素: 数组名称[索引位置] 案例: 多维数组:多个线性数组的值 二维:i

初学者入门web前端 C#基础知识:数组与集合

对于初学者,想要入门web前端,要有足够的信念和坚持,不然只会越走越远,我现在就深深的体会到. 我本是一个很拒绝代码的人,以前想过UI设计,但是在这段学习时间里,发现其实只要认真,代码并不是很难 所以我整理了一套前期学C#的知识点,对于后期学习JavaScript有很大的帮助. 一.数组与集合数组:能存放任意多个同类型的数据 数据项:类型相同 ①每一个数据型都有一个编号(索引或下标) ②数据的索引(下标)是一个int类型的数字 ③从0开始,依次为数据中每一个数组项编号 数组的声明与赋值 声明:数

编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议79~82)

建议79:集合中的哈希码不要重复 在一个列表中查找某值是非常耗费资源的,随机存取的列表是遍历查找,顺序存储的列表是链表查找,或者是Collections的二分法查找,但这都不够快,毕竟都是遍历嘛,最快的还要数以Hash开头的集合(如HashMap.HashSet等类)查找,我们以HashMap为例,看看是如何查找key值的,代码如下: 1 public class Client79 { 2 public static void main(String[] args) { 3 int size =

c#重点[集合类型]异常,数组,集合ArrayList,List&lt;&gt;,hashTable,hashtable泛型(Dictionary)

1.foreach[对一些数组或集合进行遍历] foreach(类型 变量名 in 集合对象){语句体} 1 //定义一个数组 2 int [] sNum1={19,33,27,57,45,43 }; 3 foreach(var i in sNum1) 4 { 5 Console.WriteLine(i); 6 } foreach for循环 1 int[] str1 = {19,33,27,57,45,43 }; 2 //for循环遍历 3 for (int i=0;i<str1.length

数组、集合、泛型解析——【新生入学系统】

一.概念(from 百科) 数组:把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标. 集合:集合是一组可变数量的数据项(可为0)的组合,这些数据项可能共享某些特征,需要以某种操作方式一起进行操作. 泛型:在程序编码中一些包含参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象. 二.进化史 开始用内存中的一个位置映射一个值,用"变量"来使用这个值.进一步发展成,用变量来引用一组值,数组诞生.后来有了集合,它是更强的的数组,依

改善java程序的151个建议--数组和集合

60.性能考虑,数组是首选,在基本类型处理方面,数组还是占优势的,而且集合类的底层也都是通过数组实现,建议在性能要求较高的场景中使用数组替代集合. 61.如果有必要,使用变长数组:我们可以通过对数组扩容"婉转"地解决数组扩容问题,下面采用的是Arrays数组工具类的copyOf方法,产生了一个newLen长度的新数组,并把原有的值拷贝了进去,之后就可以对超长的元素进行赋值了 62.警惕数组的浅拷贝 Person[] p=new Person[5]; Person[] p2=Arrays

数组、集合与泛化

从VB.C#到VB.net,在变量的使用中总少不了数组的影子,它不仅可以快速而容易地从头到尾遍历元素,还可以快速的修改元素.但是用的多了自然就发现了的它的缺点,当两个元素之间添加元素时就比较困难了,因为在创建时事先指定了数组变量的大小使用时又不能随意增改,再加上链表.堆.栈等需求的增加,数组已经显得力不从心了,由此发展出了集合,即传说中的动态数组,它是.NET Framework提供的用于数据存储和检索的专用类,这些类提供了对堆栈.队列.列表和哈希表的支持. 但是集合都依赖于Object基类,使

再议指针---------函数回调(qsort函数原理)

我们能否写一个这样的函数: 可以对任何类型数据排序 任何人在使用该函数不需要修改该函数代码(即:用户可以不必看到函数源 码,只会调用就行) 思考: 用户需要排序的数据的类型千变万化,可能是int型,也有可能是自定义的结构体类型,各种类型的大小比较规则是不一样的,这样看来实现一个这样全能的排序函数似乎不可能. 但具体需要排序的类型应按照什么规则确定大小只有使用该函数的用户最清楚,那我们可不可以把实现比较大小的功能交给用户来完成了,到时候用户只需告诉该函数比较规则(函数)在什么位置,这样排序函数不就

返回零长度的数组或者集合,而不是null

<<Effective Java>> 第四十三条:返回零长度的数组或者集合,而不是null 如果一个方法的返回值类型是集合或者数组 ,如果在方法内部需要返回的集合或者数组是零长度的,也就是没有实际对象在里面, 我们也应该放回一个零长度的数组或者集合,而不是返回null.如果返回了null,客户端程序员就要检测返回的是不是null,然后才能 进行下一步操作,否则就会引发NullPointException.但是如果是返回的的是空数组或者集合,就不会再后续的使用这个对象上,引发 空指针