天天看点

C#笔记12 自定义集合和常用集合

文章目录

      • 自定义集合
        • 什么是迭代器
        • 迭代器 Enumerator
        • 集合 IEumerable
        • yield return和yield break
      • 常用集合
        • 字典Dictionary
        • 栈Stack、队列Queue在数据结构和算法中常用
        • 双向列表LinkedList、IComparable、IList、[]索引运算符

自定义集合

什么是迭代器

  • 首先通过场景实现。
class MyList{
	private int[] Nums { get; set; }
	public MyList(int n){
		Nums = new int[n];
		
		var r = new Random();
		foreach(var i in Nums){
			Num[i] = r.Next(1,10);
			// 上句会报错,因为foreach是只读,无法赋值。
		}
		// 因此不用foreach(),用for如下
		for(int i=0; i<n; i++){
			Num[i] = r.Next(1,10);
		}
	}

	private int Index = -1;
	public bool MoveNext(){
		Index++;
		return Index < Nums.Length;
	}
	
	public int Current {get {return Nums[Index];}}
}

class Program{
	...Main(..){
		var list = new MyList(5);
		while(list.MoveNext()){
			Console.WriteLine(list.Current);
		}
		// 这里改为迭代器更为方便
	}
}
           
  • 上述程序中,如果想重新打印两次list,则需要在Main()中嵌套两层while(){}。
  • 但是两个while共用一个list,list中的Index只用于维护一层循环。因此引入迭代器。

迭代器 Enumerator

  • 把上例中list中用于迭代的部分拉出来单独做一个迭代器,再增加一个方法调用迭代器。
class Enumerator{
	
	private int[] Nums = null;	
	public Enumerator(int[] nums){
		Nums = nums;
	}
	
	private int Index = -1;
	public bool MoveNext(){
		Index++;
		return Index < Nums.Length;
	}
	
	public int Current {get {return Nums[Index];}}
}
           
  • 在MyList中增加方法调用迭代器。
  • 有了迭代器,在Main()中使用如下。
class MyList{
	private int[] Nums { get; set; }
	public MyList(int n){
		Nums = new int[n];
		
		var r = new Random();
		for(int i=0; i<n; i++){
			Num[i] = r.Next(1,10);
		}
	}

	public Enumerator GetEnumerator(){
		return new Enumerator(Nums);
	}
}

class Program{
	...Main(..){
	
		var list = new MyList(5);
		var e1 = list.GetEumerator();
		
		while(e1.MoveNext()){
			Console.WriteLine(e1.Current);
			
			var e2 = list.GetEumerator();
			while(e1.MoveNext()){
				Console.WriteLine("\t" + e2.Current);
			}
		}
	}
}
           
  • 其实上述也是设计模式中的迭代器模式。

集合 IEumerable

  • 类实现迭代器功能,C#中可称为集合。
  • 所以集合是实现了IEnumerable接口的类。
class MyList : IEnumerable<int>{
	
	// 接口自带方法,是因为以前没有泛型而留下的问题
	System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator(){
		throw new NotImplementedException();
	}
}
           

yield return和yield break

  • yield按照我的理解是输出迭代器中第几个值,以及用break停止。
class MyList : IEnumerable<int>{
	private int[] Nums { get; set; }
	public MyList(int n){
		Nums = new int[n];
		
		var r = new Random();
		for(int i=0; i<n; i++){
			Num[i] = r.Next(1,10);
		}
	}

	public IEnumerable<int> GetEnumerator(){
		yield return 1;
		yield return 2;
		yield return 3;
		// 调用该方法后根据循环依此输出1,2,3。
		// yield break 一般和if(){}联用。

		// 比较常用的是循环与yield return联用。
		foreach(var i in Nums){
			yield return i;
		}
	}
}

class Program{
	...Main(..){
	
		var list = new MyList(5);
		var e1 = list.GetEumerator();
		
		foreach(var i in list){
			Console.WriteLine(e1.Current);
			foreach(var i2 in list){
				Console.WriteLine("\t" + e2.Current);
			}
		}
	}
}
           
  • 迭代器在我看来就是不一口气输出,二是可以与Main()中循环一步步慢慢来。
  • 迭代器和foreach关系:能用foreach()一定有迭代器。
  • foreach不可以修改,只读。

常用集合

  1. List
  2. Dictionary<TKey, TValue>

    字典的遍历,其中涉及到哈希表存储数据,查找速度很快。

  3. SortedList、SortDic…
  4. Stack<T>
  5. Queue<T>
  6. LinkedList<T>

字典Dictionary

class Program{
	...Main(..){
		var dic = new Dictionary<int, string>();
		dic.Add(1, "a");
		dic.Add(2, "b");
		dic[1] = "aa";

		var dic1 = new Dictionary<int, Dictionary<int, string>>();
			}
		}
	}
}
           

栈Stack、队列Queue在数据结构和算法中常用

  • 比较经典的如字符串表达式求值等。
  • “(1+2)*3”,用两个栈,一个栈存操作符,一个栈存数字。

双向列表LinkedList、IComparable、IList、[]索引运算符

  • IComparable中有CompareTo()方法。
上一篇: C#笔记14 LINQ