数组用于定义长度不变的集合,但是在实际的处理过程中,我们往往对集合的大小并不确定,因此在实际的开发工作中,我们更多的需要处理集合元素。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