连载,LINQ兵法十四章,6(1of1)

hi20140509 2014-05-16 08:03:23
加精
上一篇

第六章 数组和集合

和大多数语言一样,C#也有数组。

下面都是合法的数组的定义:

int[] a1 = new int[] { 1, 2, 3, 4, 5 };
string[] a2 = new string[] { "a", "b", "c", "d", "efg" };
object[] a3 = new object[] { 1, "a", 3.2f, typeof(Program) };
object[] a4 = null;
object[] a5 = new object[] { };
object[] a6 = new object[2];


我们可以定义object的数组,里面塞进去任何类型的元素,如a3,我们可以让数组指向null,如a4,我们可以定义空数组,如a5,我们可以定义一个数组,指定长度,但是不初始化里面的元素,如a6。注意两点,一个是空数组和未初始化的数组不是一个概念,如果你有一个没有装东西的口袋和你根本没有口袋不是一回事。另一个,object[] a6 = new object[2]; 相当于 object[] a6 = new object[] { null, null };而int[] a = new int[2];则相当于 int[] a = new int[] { 0, 0 };你还可以写int[] a1 = new int[3] { 1, 2, 3 };注意,如果这样写,那么两者的元素数量必须一致。你还可以有更简单的写法:int[] a1 = { 1, 2, 3 };

既然object可以是数组,而数组类型是object的派生类,那么显然数组的数组,甚至数组的数组的数组也是合法的。很多教科书将数组的数组叫做“交错数组”,因为作为数组元素的数组的长度可以不同,比如int[][] a = new int[][] { new int[] { 1, 2 }, new int[] { 1 }, new int[] { }, new int[] { 1, 2, 3, 4 } };。这个数组的每个元素是一个int[],那么它就是(int[])[],也就是int[][],它的每个元素都是int[]就可以了,当然可以不等长,比如此例,第一个有2个元素,第二个有1个,第三个为空……。其实这很好理解。

C#也支持二维数组,三维数组,等等。比如定义一个整数的二维数组:int[,] = new int[3,2],就定义了一个3x2的二维数组,一共包含了6个元素。二维数组相当于一个矩阵。本质上说,一个二维数组,其实也是编译器玩的一个魔术,它其实就是一个x * y个元素的一维数组,而通过下标 x, y 访问它的元素的时候,其实就是访问了 x * 一维长度 + y。

你可以用多层嵌套的括号来初始化它,比如int[,] arr = { { 1, 2 }, { 3, 4 }, { 5, 6 } };或者int[,] arr = new int[3,2] { { 1, 2 }, { 3, 4 }, { 5, 6 } };。

在介绍集合之前,我们先介绍下集合初始化器。如果一个类型实现了IEnumerable,并且拥有一个Add的方法,那么我们就可以使用集合初始化器。

看下面的代码:

class Program
{
static void Main(string[] args)
{
A a = new A() { 1, 2, 3 };
}
}
class A : IEnumerable
{
public void Add(int i) { Console.WriteLine(i); }

public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}


事实上我们连GetEnumerator()都没有真正实现,这个代码是合法的。C#编译器会自动把{ 1, 2, 3 }转换成以下3行:
a.Add(1);
a.Add(2);
a.Add(3);

Console.WriteLine的输出可以证明这一点。

我们介绍几个.NET内置的集合和数据结构,它们都实现了IEnumerable,并且拥有Add方法,所以它们自然支持集合初始化器,同时它们还支持什么?

别忘了,它们支持用foreach进行遍历。前面说过的。

List<T>,它表示一个列表,列表项的顺序和调用Add添加它的顺序相同。相比较数组,List<T>可以随意添加元素,也可以随意删除元素,使用非常方便。除了List<T>,它还有几个兄弟,比如:LinkedList<T>,学过数据结构我们知道,链表在插入和删除中间元素的时候性能有优势,但是它不能连续寻址;SortedList<T>,它维护一个有序表,因此对它排序更快,但是它不保持元素原始的顺序了。这里不详细介绍,请自己看msdn。

Dictionary<TKey, TValue>,它表示一个字典,由Key和Value组成,而Key则是唯一的。你可以通过Key索引到Value。从某种程度说,其实List和数组是字典的特例,它的Key是从0开始的自然数,而Value就是对应的元素。

如果你需要Key、Value组成的集合,但是Key不是唯一的,那么可以用List<KeyValuePair<TK, TV>>,不过通过Key找Value就不那么高效和方便了。具体怎么做,等学会Linq就自然会了。除此之外,你也可以用Dictionary<TKey, List<TValue>>,将重复项归并到一个项的列表中。从这里你也可以看出来,其实我们可以灵活运用,让这些集合相互嵌套。

Tuple<>,它有个很数学的中文名字,叫元组,表示相关的几个数据构成的整体。比如KeyValuePair<TK, TV>,也可以表示为Tuple<T1, T2>。如果我们想表示一个学生的学号、姓名、语文、数学、英语成绩构成的记录,除了定义一个类以外,我们也可以表示为Tuple<int, string, double, double, double>,那么这个对象的Item1就是学号,Item2就是姓名,Item3~5就是成绩。而List< Tuple<int, string, double, double, double>>则可以表示很多学生的成绩,它构成了一个表。

Stack<T>、Queue<T>,它们表示堆栈和队列,关于什么是堆栈和队列,数据结构课程应该都学过,它们也有几个兄弟,比如ConcurrentStack和ConcurrentQueue,它们支持多线程并发操作。

对于集合,需要掌握的是如何定义,如何添加元素,如何获得元素个数,如何通过索引器随机访问,如何用foreach遍历,如何删除元素等等。需要指出的是,不要在foreach遍历的时候从List中删除非结尾的元素,否则会破坏迭代器丢出错误。

List<int> data = new List<int>() { 7, 3, 2, 5, 6, 4, 10, 9, 1, 8 };
data.RemoveAt(2);
data.RemoveAt(2);
data.Remove(6);
for (int i = 0; i < data.Count; i++)
Console.WriteLine(data[i]); // 7,3,4,10,9,1,8
Console.WriteLine();
data.AddRange(new int[] { 2, 5 });
data.Add(6);
for (int i = 0; i < data.Count; i++)
Console.WriteLine(data[i]); // 7,3,4,10,9,1,8,2,5,6
data.Sort();
Console.WriteLine();
for (int i = 0; i < data.Count; i++)
Console.WriteLine(data[i]); // 1,2,3,4,5,6,7,8,9,10
data.Clear();
data.AddRange(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
data.RemoveAll(x => x % 2 == 0);
Console.WriteLine();
for (int i = 0; i < data.Count; i++)
Console.WriteLine(data[i]); // 1,3,5,7,9
data.Reverse();
Console.WriteLine();
foreach (int i in data)
Console.WriteLine(i); // 9,7,5,3,1

Dictionary<string, string> dict = new Dictionary<string, string>()
{
{ "Apple", "苹果" }, { "About", "关于" }, { "Apply", "应用" }, { "Above", "在...之下" }, { "Academic", "学术的" }
};
dict.Add("Apologize", "道歉");
dict.Add("Apartment", "公寓");
foreach (string key in dict.Keys)
Console.WriteLine("{0}: {1}", key.ToLower(), dict[key]);
bool b1 = dict.ContainsKey("Aspect");
bool b2 = dict.ContainsKey("Apply");
bool b3 = dict.ContainsValue("学术的");
Console.WriteLine("b1={0} b2={1} b3={2}", b1, b2, b3);

Queue<int> q = new Queue<int>();
q.Enqueue(1);
q.Enqueue(2);
q.Enqueue(3);
while (q.Count > 0)
Console.WriteLine(q.Dequeue());

Console.WriteLine();

Stack<int> s = new Stack<int>();
s.Push(1);
s.Push(2);
s.Push(3);
Console.WriteLine(s.Peek());
while (s.Count > 0)
Console.WriteLine(s.Pop());


.NET没有提供Tree数据结构,所以最后留一个思考题,请实现一个Tree<T>的数据类型,并且让它和它的节点都支持IEnumerable<T>,可以递归遍历全部元素。

代码略。

下一篇
...全文
1681 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
ggqzx 2014-06-16
  • 打赏
  • 举报
回复
谢谢楼主,学习了!
游离失所 2014-06-16
  • 打赏
  • 举报
回复

public class Tree<T>
{
    public Tree()
    {
    }
    private List<T> thisNode;
    public Tree<T> nextNode
    {
        get;
        set;
    }

    public void Add(T t)
    {
        if (thisNode == null)
            thisNode = new List<T>();
        thisNode.Add(t);
    }

    public IEnumerator<T> GetEnumerator()
    {
        foreach (var temp in thisNode)
        {
            yield return temp;
        }
    }
}
挺好玩
江湖的传说 2014-05-21
  • 打赏
  • 举报
回复
validf9 2014-05-18
  • 打赏
  • 举报
回复
也不能这么说吧
buyaosowd 2014-05-18
  • 打赏
  • 举报
回复
泛型就是个垃圾
同流合污c 2014-05-18
  • 打赏
  • 举报
回复
听说比泛型好
pngg 2014-05-18
  • 打赏
  • 举报
回复
可是和java里面的泛型有什么区别呢?
c3124 2014-05-18
  • 打赏
  • 举报
回复
谢楼主分享。。。
fu3210 2014-05-18
  • 打赏
  • 举报
回复
应该是这样吧
wahahahahahaha2 2014-05-18
  • 打赏
  • 举报
回复
应该是就像java里面动泛型吧
同流合污c 2014-05-18
  • 打赏
  • 举报
回复
你以为是我叫MT吗 笑死了
kszpig 2014-05-18
  • 打赏
  • 举报
回复
是不是和C里面那个什么MT有点像啊?
valid27 2014-05-18
  • 打赏
  • 举报
回复
linq听说不错的样子
valid26 2014-05-18
  • 打赏
  • 举报
回复
请问楼主 linq究竟是个什么东西
valid25f 2014-05-18
  • 打赏
  • 举报
回复
c#里的好东西
xiaofan0122 2014-05-18
  • 打赏
  • 举报
回复
学习了学习了,谢谢
sunjoin2009 2014-05-17
  • 打赏
  • 举报
回复
热烈热烈欢呼!
SomethingJack 2014-05-17
  • 打赏
  • 举报
回复
看看楼主最后实现的例子 Tree<T>
ssa 2014-05-16
  • 打赏
  • 举报
回复
学习,linq比较喜欢的一个话题
sunylf 2014-05-16
  • 打赏
  • 举报
回复
c#?.....
加载更多回复(7)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧