C# 笔记2 - 数组、集合、文本文件处理
正在做笔记中…
任何软件编程语言都会涉及到这些基本内容——栈、队列、列表、数组、散列表等等,没有它们几乎无法完成任何工作。只是不同语言对某些数据结构由不同的封装,其中我最喜欢的还是python。道理很简单——简单方便,因此我喜欢使用python的数据结构作为对比。
文末将示范一个C#解析日志文件实战案例。
1. 随笔
在多数情况下的编程实战中,我们几乎不喜欢使用数组,主要是麻烦——数组的显著特点是,其只能存储类型一致的数据。在公认的强类型语言(java、C、C++等,当然也有部分人认为C++是弱类型,这里不做讨论。)中,组数是一种直接用于容纳一组同类数据的容器,在这一点上C#也一样,声明后就不能装其它类型:
int [] ary = new int[3]{99,98,92};
但这不是我们期待的——我们只希望获得一个箱子,这个箱子应该是可以想装什么装什么的,就像哆啦A梦的口袋一样:
(图片来源于网络)
python提供的几大基本数据类型都是这样的口袋型,其中与数组最接近的就是列表(list)
和元组(tuple)
了,都属于复合数据对象,并且自带很多方法,这里推荐一篇博客——Python序列专题,对python中的相关内容由详细地讨论。不得不说,作为一门现代的面向对象编程语言,将其作为可以直接使用的基本数据类型是更科学的。在C#中却需要通过using
语句使用其内建的库。如System.Collections
类的ArrayList
。
语言 \ 数据结构 | 栈 | 队列 | 链表 | 数组 | 字典(哈希表/散列表) | 列表(一种序列) | 元组 | 集合/集 |
python | - | collections.deque | - | array.array | dict | list | tuple | set(集合) |
C# | Stack | Queue | LinkedList | Array | Hashtable | ArrayList | Tupls | HashSet(集) |
2. C# 数组
2.1 数组的声明和初始化
可以一步完成:
int [] a = new int[5] { 4, 6, 2, 5, 7};
输出结果
:
当然也可以分开完成:
int [] a; a = new int[5] { 4, 6, 2, 5, 7};
输出结果
:
2.2 对数组赋值
a[1] = 6;
输出结果
:
2.3 索引数组
输出结果
:
2.4 使用增强型for语句foreach
遍历数组
输出结果
:
2.5 多维数组
2.5.1 声明一个多维数组
float [,] a; // 声明一个float型二维数组a int [ , , ] b; // 声明一个int型三维数组b
3. C# 集合
3.1 动态数组ArrayList
【例1】初始化、添加元素
// 省去部分无关主题代码 ArrayList a = new ArrayList(); a.Add(6); a.Add("AaBbCc") a.Add(3.14) Base.print(a); // 在控制台打印列表a
输出结果
:
[6, "AaBbCc", 3.14]
【例2】获取ArrayList列表长度
class Base... Base.print(a.Count); // 通过 ArrayList 的 Count 属性获得 实际包含的元素个数
输出结果
:
3
【例3】对ArrayList进行索引
ArrayList a = new ArrayList(); a.Add(6); a.Add("AaBbCc"); a.Add(3.14); for (int i = 0; i < a.Count; i++) { Base.print(a[i]); }
输出结果
:
6 "AaBbCc" 3.14
- 但是与python中的列表直接用索引值-1来获取最后一个元素不同,ArrayList无法这样获取最后一个元素,需要获取最后一个元素需要按照长度来:
ArrayList a = new ArrayList(); a.Add(6); a.Add("AaBbCc"); a.Add(3.14); Base.print(a[a.Count - 1]);
输出结果
:
3.14
【例4】对ArrayList进行排序
可以使用ArrayList.sort()
方法
ArrayList a = new ArrayList(); a.Add(6); a.Add(7); a.Add(2); a.Add(4); Base.print(a); a.Sort(); Base.print(a);
输出结果
:
[6, 7, 2, 4] [2, 4, 6, 7]
【例4】在ArrayList的指定位置插入元素
可以使用ArrayList.Insert()
方法
a.Add(6); a.Add(7); a.Add(2); a.Add(4); Base.print("插入元素前:"); Base.print(a); a.Insert(1,"elem"); Base.print("在第1个位序后插入元素后:"); Base.print(a);
输出结果
:
插入元素前: [6, 7, 2, 4] 在第1个位序后插入元素后: [6, "elem", 7, 2, 4]
3.2 栈Stack
栈的特点是,后进先出FILO。C# 提供了
Stack
对象。
该对象主要提供了以下方法/属性:
属性/方法 | 功能描述 |
Stack.Count |
Stack 中包含的元素个数 |
Stack.Pop() |
出栈(移除并返回在 Stack 的顶部的对象。) |
Stack.Push() |
进栈(向 Stack 的顶部添加一个对象) |
Stack.Peek() |
查看(仅返回)栈顶元素。 |
Stack.Contains() |
判断某个元素是否在 Stack 中。 |
Stack.Clear() |
从 Stack 中移除所有的元素。 |
Stack.ToArray() |
复制 Stack 到一个新的数组中 |
【例1】
3.3 队列Queue
队列的特点是先进先出FIFO,C# 提供了队列对象
Queue
该对象主要提供了以下方法/属性:
属性/方法 | 功能描述 |
Queue.Count |
Queue 中包含的元素个数 |
Queue.Enqueue |
入队(向 Queue 的末尾添加一个对象) |
Queue.Dequeue() |
出队(移除并返回在 Queue 的开头的对象) |
Queue.TrimToSize() |
置容量为 Queue 中元素的实际个数 |
Queue.Contains( object obj) |
判断某个元素是否在 Queue中。 |
Queue.Clear() |
从 Queue中移除所有的元素。 |
Queue.ToArray() |
复制 Queue 到一个新的数组中 |
3.4 链表
3.5 字典
4. 实战——日志文件(文本文件)解析案例
4.1 案例概述
现有一个txt日志文件内容如下:
| | 表格标题1 | | 日期 | 表头1 | 表头2 | 表头3 | 表头4 | 表头5 | 表头6 | 表头7 | 表头8 | 表头9 | 表头10 |时间 | |2009-01-25| ACD | 254 | 583 | 777 | QWF | 753 |752 | 3 | 3546.99| 6.66| 20:46 | |2009-01-25| ACD | 396 | 463 | 999 | QWG | 432 |342 | 7 | 3456.66| 6.66| 20:46 | | 总计 | | 746 | 1,046 | 1,776 | | 1,185 | 1,184 | 10 | 7,003.65 | 22.00| 880.16| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 表格标题2 | | | | 表头1 | 表头16 | 表头3 | 表头4 | 表头14 | 表头8 | 表头9 | 表头11 | 表头12 |表头13|表头17|时间| | 内容1 | ABC | 456 | 666 | 453 | 60 | 4,258.00| 777.16| LJG |5357 |58 | 20:46| | 总计 | | 456 | 666 | 453 | 60 | 4,258.00 | 777.16| |5357|58|20:46| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 表格标题3 | | 日期 | 表头1 | 表头3 | 表头4 | 表头7 | 表头13 | 表头15 | 表头17 | 表头18 | 表头19 | 表头12 |时间| |2009-01-25 | HGF | 267 | 106 |JFG | 666 | 888.00| 222.00| 4666.00| 2626.00| 内容7 | 20:46| |2009-01-25| ACD | 475 | 109 |JFG | 777 | 888.00| 222.00| 6777.00| 2626.00| 内容7 |20:46 | | 总计 | | 742 | 215 | | 1443 | 1776.00 | 444.00 | 11443.00 | 5252.00 | | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 表格标题4 | | 日期 | 表头1 | 表头3 | 表头4 | 表头25 | 表头22 | 表头9 | 表头20 | 表头21 | 表头20| 表头21 | 时间 | |2009-01-15| ACD | 453 | 345 | 33 | 99 | 550.00| 715.00 | 785.00 | -50.00| 0.01| 16:26 | |2009-01-15| ABC | 345 | 2105 | 44 | 88 | 650.00| 615.00 | 705.00 | 70.00| 0.02| 16:26 | |2009-01-18| HGF | 646 | 654 | 55 | 77 | 433.00| 432.00 | 429.00| 66.00| 1.00| 16:26 | |2009-01-18| HGF | 2634 | 35 | 66 | 66 | 393.00| 932.00 | 429.00| 99.00| 0.00| 16:26 | |2009-01-18| HGF | 345 | 5 | 77 | 55 | 439.00| 43.00 | 499.00| 66.00| 2.30| 16:26 | |2009-01-18| HGF | 5436 | 123 | 88 | 44 | 463.00| 92.00 | 429.00| -30.00| 1.00| 16:26 | |2009-01-18| HGF | 26 | 456 | 99 | 33 | 396.00| 42.00 | 429.00| 50.00| 0.06| 16:26 | | 总计 | | | | | | | | | | | 内容6 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 表格标题5 | | | 表头1 | 表头3 | 表头4 | 表头25 |表头26| 表头22 |表头9| 表头9 | 表头21 | 表头20 | 表头21 | 时间 | | 内容1 | ASF | 22 | 30 | 965.41 | 0 | 0.00| 7665.40| 9119.00| 12,0.00| 0.00| 12:29 | | ABC | DGN | 33 | 10 | 47.30 | 300 | 444.00| 7669.00| 1805.00| 15,00.00| 0.00| 12:29 | | ACD | DFG | 44 | 20 | 780.16 | 0 | 666.00| 6660.00| 1780.00| -190.00| 0.00| 12:29 | | ACD | DGN | 55 | 80 |252.15 | 0 | 888.00| 2266.15| 3790.00| 4,80.00| 0.00| 12:29 | | ABC | DFG | 666 | 25 | 4393 | 0 | 222.00| 6688.00| 299.00| -8,250.00| 0.00| 12:29 | | 总计 | | 820 | 165 | | 300 | 2220 | | -6340 | | 0.00 | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们需要将该文件中所有的表解析出来,得到一种便于索引的结构。比如python第三方库pandas中的DataFrame那样,每一个对应一张表。可以回忆下在写python中的作法:
以上是python在jupyter环境中实现的。可以看到,我们只要给定值即可出来整个表。这是接下来通过C#实现与之相同的功能。
4.2 C# 读取文本文件
这是万丈高楼第一层,就是需要在C#中读取这个文本。我们希望的是读取后按行处理。
这需要用到System.IO
中的StreamReader
对象,详细用法请查询手册。
现给出代码如下:
using System; using System.IO; using System.Collections; class Base... //(已省略) class Parser { public static void LogReader(string path) { /* 读取 */ StreamReader sr = new StreamReader(path); string line; while ((line = sr.ReadLine()) != null) { Base.print(line); } } } class Program { public static void Main() { /* 指定路径 */ string file_path= @"C:\Users\李俊才\Documents\WeChat Files\wxid_alacfd07418y22\FileStorage\File\2021-02\puretextlog.txt"; /* 解析日志 */ Parser.LogReader(file_path); } }
运行结果
(部分截图):