数组用于定义长度不变的集合,但是在实际的处理过程中,我们往往对集合的大小并不确定,因此在实际的开发工作中,我们更多的需要处理集合元素。ArrayList是一个可变数组,其变在于两点:
集合的大小可变
集合中存放的数据类型可变
我们看以下的代码案例:
System.Collections.ArrayList list = new System.Collections.ArrayList();
System.Console.WriteLine(list.Count);
list.Add(1);
list.Add(12.21);
list.Add("Hello");
System.Console.WriteLine(list.Count);
list.Add(10);
list.Add(short.MaxValue);
list.Add(DateTime.Now);
System.Console.WriteLine(list.Count);
我们可以发现,在ArrayList中可以放入各种不同类型的数据,其不象数组那样的严格,而且元素的个数是随我们放入的元素的多少进行变化的。ArrayList不但可以放入元素,还可以搜索、删除元素。
System.Console.WriteLine(list.IndexOf("Hello"));
list.RemoveAt(1);//移除位置为2的元素
System.Console.WriteLine(list[1]);
list.Remove(1);//移除和1相对的元素
System.Console.WriteLine(list[0]);
以上代码运行的结果如图3.1.24:
图3.1.24
值得注意的是,Remove对值类型和引用类型的作用不一样,看以下代码:
System.Collections.ArrayList list = new System.Collections.ArrayList();
list.Add(12);// 值类型
list.Add(new DateTime(2009, 12, 9));// 值类型
list.Add(new int[] { 1, 2, 3 });//引用类型
//查找值的位置
System.Console.WriteLine(list.IndexOf(12));
System.Console.WriteLine(list.IndexOf(new DateTime(2009, 12, 9)));
System.Console.WriteLine(list.IndexOf(new int[] { 1, 2, 3 }));
//移除
list.Remove(12);
list.Remove(new DateTime(2009, 12, 9));
list.Remove(new int[] { 1, 2, 3 });
//遍历
for (int i = 0; i <= list.Count - 1;i++ )
{
System.Console.WriteLine(list[i]);
}
int和DateTime是值类型,ArrayList在匹配的时候按值匹配,而数组是引用类型,匹配的时候按引用的地址匹配,因此在使用Remove和IndexOf时候要注意。通过这样的现象我们可以得到一个推测,Remove其实是RemoveAt(IndexOf)的组合。
由于ArrayList中可用存放很多类型,因此我们在处理集合的时候需要注意类型的转换,以下代码试图在对集合中数值进行求和。
System.Collections.ArrayList list = new System.Collections.ArrayList();
list.Add(1);
list.Add(12.21);
list.Add("Hello");
list.Add(10);
list.Add(short.MaxValue);
list.Add(DateTime.Now);
double sum=0;
for (int i = 0; i <= list.Count - 1;i++ )
{
if (list[i].GetType() == typeof(int))
{
sum += (int)list[i];
}
if (list[i].GetType() == typeof(double))
{
sum += (double)list[i];
}
}
System.Console.WriteLine(sum);
如果你在ArrayList中存放的数据类型很杂,则在处理数据的时候要分外小心。ArrayList在对待插入的是集合的时候有两种模式,注意以下代码:
System.Collections.ArrayList list = new System.Collections.ArrayList();
list.Add(new int[] { 1, 2, 3, 4, 5 });
list.AddRange(new int[] { 1, 2, 3, 4, 5 });
for (int i = 0; i <= list.Count - 1; i++)
{
System.Console.WriteLine(list[i]);
}
运行的结果如图3.1.25:
图3.1.25
可以发现使用Add是简单的将一个对象插入集合,而AddRange是将集合解开,将集合中的每一个值插入当前集合。
使用ArrayList在有些方面比数组要方便的多,以下代码是使用ArrayList重写发牌的应用。
System.Collections.ArrayList pokerList = new System.Collections.ArrayList();
for (int i = 0; i <= 13 - 1; i++)
{
for (int j = 3; j <= 6; j++)
{
string title = "";
switch (i + 1)
{
case 1:
title = "A";
break;
case 11:
title = "J";
break;
case 12:
title = "Q";
break;
case 13:
title = "K";
break;
default:
title = (i + 1).ToString();
break;
}
pokerList.Add(string.Format("{0}{1}", (char)j, title));
}
}
pokerList.Add(string.Format("{0}", (char)1));//小鬼
pokerList.Add(string.Format("{0}", (char)2));//大鬼
上述代码产生的结果和用数组的结果是一致的,但代码简单了些。以下这段代码演示了如何输出集合中的每个元素。
for (int i = 0; i <= pokerList.Count - 1; i++)
{
System.Console.Write("{0,-4}", pokerList[i]);
//每13张牌输出一行
System.Console.Write("{0}", (i + 1) % 13 == 0 ? "/n" : "");
}
System.Console.WriteLine();
然后我们还是原先的思路发牌,不过代码会简化很多。
string[] player1 = new string[18];
string[] player2 = new string[18];
string[] player3 = new string[18];
System.Random r = new Random();
for (int i = 0; i <= player1.Length - 1; i++)
{
int index = r.Next(0, pokerList.Count);
player1[i] = (string)pokerList[index];
pokerList.RemoveAt(index);
index = r.Next(0, pokerList.Count);
player2[i] = (string)pokerList[index];
pokerList.RemoveAt(index);
index = r.Next(0, pokerList.Count);
player3[i] = (string)pokerList[index];
pokerList.RemoveAt(index);
}
现在我们得到的结果大致如图3.1.26:
图3.1.26
初学者注意
ArrayList 接受 null 引用作为有效值并且允许重复的元素。
3.1.6 Stack和Queue:后进先出和先进先出
Queue是先进先出的集合而Stack是后进先出的集合。这两个集合在日常的工作中也经常会用到。Queue相当我们去银行柜台排队,大家依次鱼贯而行。Stack象我们家中洗碗,最后洗好的碗叠在最上面,而下次拿的时候是最先拿到最后叠上去的碗。了解了这样场景,就很容易明白Stack和Queue可用在哪里了。
比如我们为医院作一个排队叫号的系统,那肯定是选择Queue对象处理。如果我们要为出牌或下棋准备一个场景,那肯定是选择Stack,因为通过Stack至少可用提供用户悔棋啊。
以下是Queue的代码演示:
System.Collections.Queue q = new System.Collections.Queue();
for (int i = 0; i <= 10; i++)
{
q.Enqueue(i);//入队
}
System.Console.WriteLine(q.Count);
while (q.Count > 0)
{
System.Console.WriteLine(q.Dequeue());//出队
}
运行的结果如图3.1.27所示:
图3.1.27
以下是Stack的代码演示:
System.Collections.Stack s = new System.Collections.Stack();
for (int i = 0; i <= 10; i++)
{
s.Push(i);//入栈
}
System.Console.WriteLine(s.Count);
while (s.Count > 0)
{
System.Console.WriteLine(s.Pop());//出栈
}
虽然放置元素的次序和Queue一样,但取出的顺序正好相反,如图3.1.28:
图3.1.28