一、使用JSON进行数据传输
1.什么是JSON
JSON官网www.json.org/json-zh.htm… JSON (JavaScript Object Notation) 的轻量级数据交换格式能够替代XML进行数据传输,首先,它是一个字符串,一个有规则的字符串。然后它的表现形式是键值对的,有点像我们前面学的字典Dictionary,以下是JSON的格式,我们可以看到是一组组键值对,在做web开发的时候我们 就是通过JSON来实现接口数据的传输,我们可以看到JSON数据是非常直观的,更易于我们理解和查看,而且JSON也是支持c#的。
2.JSON的语法规则
根节点可以是对象也可以是数组
{
"person": {
"name": "pig",
"age": "18",
"sex": "man",
"hometown": {
"province": "江西省",
"city": "抚州市",
"county": "崇仁县"
}
}
}
也可以是数组的形式
[ { "name": "pig", "age": "18", "sex": "man" }, { "name": "cate", "age": "12", "sex": "woman" } ]
复制代码
重写类中的ToString()方法,这样我们去打印对象的时候会打印出对应字段或属性
3.书写JSON文本
4.引入JSON库文件(LitJSON)
1.两种引入LitJSON的方式
(1) 在项目依赖中引入LitJSON.dll文件
(2) 在项目依赖的NuGet中搜索LitJSON进行添加
2.使用泛型去解析JSON(转成对象数组或者list列表)
注意开头要:using:LitJSON;
转化成对象数组的形式
也可以转成list列表
5.将对象转成JSON格式的字符串
6.将数组写入txt文件中
int[] intArray = { 1, 2, 3, 4, 5, 6 };
string json = JsonMapper.ToJson(intArray);
File.WriteAllText("./1.txt", json);
7.京东联系题: 需求:获取京东首页面菜单栏的数据,并且有层次关系,数组里面包含对象,对象中可以包含数组,数组包含菜单元素
public class Menu
//使用一个静态方法帮我们创建对象
{
//无参的构造方法
public Menu()
{
this.firstMenu = FirstMenu;
}
//定义一个静态类集合和非静态类集合
public List<string> firstMenu;
private static List<string> FirstMenu;
public static Menu getMenu(List<string> MenuList)
{
FirstMenu = MenuList;
return new Menu();
}
}
//main方法的开始-----------------
//案例:获取京东页面的htnl,将京东菜单栏数据写入txt文件中
string files = File.ReadAllText("./1.html");
//因为换行影响我们提取需要的元素,所以我们利用换行来提取我们需要的。
//干脆把</li>后面加上换行,每次去匹配的内容是没有换行的。
//利用这个特点,我们匹配谁就给谁加上换行符
List<Menu> MyMenu = new List<Menu>();
//将获取到的html内容的换行去掉
files = files.Replace("\n", "");
//string pattern1 = "<li\\s+class=\"cate_menu_item\".+>.+</li>"; //?匹配的时候最小子串
string pattern1 = "<li\\s+class=\"cate_menu_item\".+?</li>"; //.+? 开启贪婪模式 匹配的是最小子串
string pattern2 ="<a.+class=\"cate_menu_lk\".+>(.+)</a>";
MatchCollection mc = Regex.Matches(files, pattern1);
foreach(Match m in mc)
{
if (m.Success)
{
Console.WriteLine(m);
List<string> MenuList = new List<string>();
//匹配每组a当中的值
string file = Convert.ToString(m).Replace("</a>", "</a>\n");
MatchCollection mc2 = Regex.Matches(file, pattern2);
foreach (Match j in mc2)
{
MenuList.Add(j.Groups[1].ToString());
}
//将列表赋值给对象的一个字段,将对象放入列表中
MyMenu.Add(Menu.getMenu(MenuList));
}
}
//将列表转化成json写入
string json = JsonMapper.ToJson(MyMenu);
File.WriteAllText("./jingdong.txt",json);
相关链接:
Json校验格式化工具: www.bejson.com/
Josn编辑器: www.bejson.com/jsoneditoro…
二、其他几种数据集合
1.栈Stack
Stack是c#为我们封装好的一个类,本质是Object[]数组,只是封装了特殊的存储规则,Stack是栈存储容器,栈是一种先进后出的数据结构,先存入的数据后获取,后存入的数据先获取
1.创建一个栈对象
需要using:System.collections;
2.栈的相关操作
- 压(入)栈(可以是基本数据类型和引用数据类型)
- 弹栈,刚才最后入栈的是new Test(),所以等下出栈第一个应该是一个对象(后进先出)
- 查询栈中的值
- 查看栈顶的值
- 查看元素是否在栈中
- 栈中改变元素只能是压栈和弹栈还有清空
- 获取栈中的长度 stack.Count
- 使用foreach遍历栈
- 循环弹栈
栈的代码汇总:
//创建一个栈
Stack s = new Stack();
Person p = new Person("heihei",12);
//入栈,数据类型可以不相同
s.Push(1);
s.Push("helloworld");
s.Push('d');
s.Push(p);
//查看栈中的值 只能读到栈顶的值
//Console.WriteLine(s.Peek); //打印的是一个对象
//需要读取里面所有的值
int length = s.Count; //放在for循环的话长度每次都会发生变化
while (s.Count > 0)
{
//获取栈顶的值
Object j = s.Peek();
Console.WriteLine(j);
s.Pop(); //出栈
}
栈的相关练习题
编写一个方法计算任意一个十进制数的二进制数,使用栈的结构方式存储,之后打印出来
分析:在进行整数的进制转化中,我们从下往上取余数刚好满足栈先进后出的原理,这时候我们可以把每次得出的余数存入栈中,并且本身的整数也要进行除2的改变,完成入栈操作后,我们就可以进行出栈while循环取值了,就可以完成上述案例。
2.队列Queue
Queue是一种先进先出的数据结构,就像我们排队一样,先排在前面的人先出去
1.队列的相关操作
- 入队列(Enqueue)
- 出队列(Dequeue)
- 查询队列(与栈类似,先是获取最顶上的元素)
- 删除队列
- 遍历队列
//队列:先进先出
Queue q = new Queue();
//入队列
q.Enqueue("hello");
q.Enqueue(10);
q.Enqueue('d');
//出队列
//q.Dequeue(); //hello出队列了
//获取的是第一个队列顶的值
//Console.WriteLine(q.Peek()); // 10
//循环遍历队列
while(q.Count > 0)
{
Console.WriteLine(q.Peek());
q.Dequeue();
}
//Console.WriteLine(q.Contains("hello")); //出队列了表示就没有这个元素了
//清空队列
//q.Clear();
//Console.WriteLine(q); //System.Collections.Queue
队列练习题
使用队列存储消息,一次性存10条消息,每隔一秒打印一条消息,控制台打印消息时要有明显的停顿感,每隔一秒使用Thread.Sleep(1000)
Queue q2 = new Queue();
for(int i = 0; i < 10; i++)
{
string str = "第" + (i+1) + "条消息";
q2.Enqueue(str);
}
//遍历队列
while(q2.Count > 0)
{
Console.WriteLine(q2.Peek());
q2.Dequeue();
Thread.Sleep(1000);
}
3.哈希表
一、什么是Hashtable
Hashtable,中文叫哈希表。它里面的英文Hash,音译是哈希。但Hash还有另一个翻译,就是“散列”,所以也叫散列表。
Hashtable是一个集合。集合是数据结构的一种,数据结构有集合、线性、树形、图形等。
Hashtable可用于存储键值对。
二、C#中如何声明一个Hashtable
您直接new一个Hashtable对象即可,如下所示:
Hashtable ht = new Hashtable();
三、如何添加和删除
通过Add和Remove方法可以给Hashtable添加或者删除项。
Hashtable ht = new Hashtable();
ht.Add("name", "蔡徐坤");
ht.Add("id", 123);
//移除元素
ht.Remove("id");
四、如何遍历
Hashtable的每个项是DictionaryEntry对象,如下:
//1.遍历哈希表
foreach (DictionaryEntry i in ht)
{
Console.WriteLine(i.Key);
Console.WriteLine(i.Value);
}
Console.WriteLine("------------------------------");
//2.遍历键
foreach (var i in ht.Keys)
{
Console.WriteLine(i);
}
Console.WriteLine("------------------------------");
//遍历值
foreach (var i in ht.Values)
{
Console.WriteLine(i);
}
//遍历哈希表的时候有点类似字典的遍历,在这里我们回顾一下遍历字典的操作:
五、判断指定元素是否存在
Console.WriteLine(ht.Contains("id"));
Console.WriteLine(ht.ContainsKey("id"));
Console.WriteLine(ht.ContainsValue("123"));
完整代码如下:
//哈希表
Hashtable ht = new Hashtable();
ht.Add("name", "蔡徐坤");
ht.Add("id", 123);
//哈希表里面键名都是唯一的,不能重复添加相同的键名,但是可以覆盖
//Console.WriteLine(ht["name"]);
//1.遍历哈希表
foreach (DictionaryEntry i in ht)
{
Console.WriteLine(i.Key);
Console.WriteLine(i.Value);
}
Console.WriteLine("------------------------------");
//2.遍历键
foreach (var i in ht.Keys)
{
Console.WriteLine(i);
}
Console.WriteLine("------------------------------");
//遍历值
foreach (var i in ht.Values)
{
Console.WriteLine(i);
}
//移除元素
ht.Remove("id");
//判断元素是否存在
Console.WriteLine(ht.Contains("id"));
Console.WriteLine(ht.ContainsKey("id"));
Console.WriteLine(ht.ContainsValue("123"));
运行一下,代码输出结果如下图:
4.综合练习-
//创建一个简单的链表类--实现增删查功能
namespace _1026链表
{
//创建一个简单的链表类
public class LinkList<T>
{
public LinkNode<T> head;//存放的头结点
public LinkNode<T> last;//存放的尾结点
//添加的方法,模仿列表的方法
public void Add(T value)
{
//新建一个节点
LinkNode<T> node = new LinkNode<T>();
//给新建的节点赋值,值来源你调用得到传入的value
node.value = value;
//链表有可能是空的,[一开始是空的,后面添加之后就不为空了]
if (head == null)
{
head = node;
last = node;
}
else //插入到尾结点的后面
{
//将插入的节点作为尾结点,last.nextNode不在指向为null,原来的尾结点存放的是新插入节点(新尾结点的)的地址
last.nextNode = node;
//将新插入的值作为尾结点的值
last = node;
}
}
//查询的方法 输入一个值 帮我查询返回该节点
public LinkNode<T> Find(T value) //head.value.Equals(value) 判断value是不是对象中的value字段的值
{
//每次从头结点开始遍历,将头结点赋值给一个新的节点接收【如果没有提前插入元素的话,这里查询会报错,head头结点为空】
LinkNode<T> node = head;
//直到一个节点为空,也就是尾结点的下一个节点为空,这时候就跳出循环
while (node != null)
{
//每次循环判断节点中的字段value的值是不是我传进来的值
if (node.value.Equals(value))
{
//如果是就返回对应的节点
return node;
}
//每次循环改变node的值,移到下一个节点进行下一轮的判断
node = node.nextNode;
}
return null; //没有查询到返回null
}
//删除操作
public void Remove(T value) //移除某个值的节点 先找到节点,有就删除,没有就不用删除-啥都不做
{
//没有节点,从头结点开始遍历
LinkNode<T> node = head;
while (node != null)
{
//1.只有一个节点的情况
if (head.nextNode == null)
{
head = null;
last = null;
//删除头节点之后跳出循环
return;
}
else
{
//2.多个节点的情况移除头结点 只需要将head = head.nextNode
if (head.value.Equals(value))
{
//原来的头结点被删除之后,下一个节点作为新的头结点,head.nextNode存放的就是原来头结点下一个地址
//把下一个节点的地址重新赋值给头节点,作为新的头节点
head = head.nextNode;
}
}
//每次循环判断节点中的字段value的值是不是我传进来的值
if (node.nextNode.value.Equals(value))
{
Console.WriteLine(222);
//3.如果有多个节点,移除最后的节点 last等于前一个节点 前一个节点的nextNode等于空
if (last.value.Equals(value))
{
Console.WriteLine(111);
node.nextNode = null;
last = node;
}else
{
//4.移除中间的节点 该节点的前一个的节点指向下下个节点
node.nextNode = node.nextNode.nextNode;
Console.WriteLine(333);
}
return;
}
//每次循环改变node的值,移到下一个节点进行下一轮的判断
node = node.nextNode;
}
return; //没有该节点的值
}
}
//链表节点类
public class LinkNode<T>
{
public T value;//数据域
public LinkNode<T> nextNode; //后指针域
public LinkNode<T> previous; //前指针域
}
internal class Program
{
static void Main(string[] args)
{
//new一个LinkList
LinkList<string> list = new LinkList<string>();
list.Add("afsfsf");
Console.WriteLine(list.Find("afsfsf").value);
list.Add("hello");
Console.WriteLine(list.Find("hello").value);
list.Add("hi");
Console.WriteLine(list.Find("hi").value);
list.Remove("hi");
//成功移除掉
Console.WriteLine(list.Find("hi") == null);
}
}
}
这个创建链表实现增删查很经典,需要多加回顾。
5.LinkedList
C# LinkedList 类使用链表的概念。它允许我们快速插入和删除元素。它可以有重复的元素。它位于 System.Collections.Generic 命名空间中。
它允许我们在之前或最后一个索引处添加和删除元素。
一、创建一个LinkedList对象
LinkedList<string> list = new LinkedList<string>();
二、往链表里面添加元素
list.AddFirst("头节点");
list.AddLast("尾节点");
三、获取头结点和尾节点
Console.WriteLine(list.First.Value);//list.First表示找到头结点
Console.WriteLine(list.Last.Value);
四、表示在某个节点的前面或后面插入一个节点
list.AddBefore(list.First, "新头"); //表示在某个节点的前面插入一个新结点作为头结点
Console.WriteLine(list.First.Value);
list.AddAfter(list.Last,"新的尾"); //表示在某一个节点的后面插入一个新的节点值作为新的尾
Console.WriteLine(list.Last.Value);
五、寻找指定的节点
LinkedListNode<string> node = list.Find("尾节点");
if (node != null)
{
Console.WriteLine(node.Value);
}
六、移除指定的节点
//移除节点
list.Remove("新的尾");
list.Remove("新头");
Console.WriteLine(list.Last.Value); //移除后头结点作为第一个
Console.WriteLine(list.First.Value); //移除后尾结点作最后一个
七、查询该节点是否在链表中,返回bool值
Console.WriteLine(list.Contains("头节点"));
八、遍历链表
foreach(string s in list)
{
Console.WriteLine(s);
}
九、完整代码如下:
using System.Collections;
namespace demo1028
{
internal class Program
{
static void Main(string[] args)
{
//集合类 链表类
LinkedList<string> list = new LinkedList<string>();
//添加
list.AddFirst("头节点"); //插入头结点的前面,传入插入节点的值
//拿到头节点:
Console.WriteLine(list.First.Value);//list.First表示找到头结点
list.AddLast("尾节点");
Console.WriteLine(list.Last.Value); //list.First表示找到尾结点
list.AddBefore(list.First, "新头"); //表示在某个节点的前面插入一个新结点作为头结点
Console.WriteLine(list.First.Value);
list.AddAfter(list.Last,"新的尾"); //表示在某一个节点的后面插入一个新的节点值作为新的尾
Console.WriteLine(list.Last.Value);
//找到指定的节点 没有找到返回空
LinkedListNode<string> node = list.Find("尾节点");
if (node != null)
{
Console.WriteLine(node.Value);
}
Console.WriteLine("--------------------------------------");
//移除节点
list.Remove("新的尾");
list.Remove("新头");
Console.WriteLine(list.Last.Value); //移除后头结点作为第一个
Console.WriteLine(list.First.Value); //移除后尾结点作最后一个
//查询该节点是否在链表中,返回bool值
Console.WriteLine(list.Contains("头节点"));
Console.WriteLine("--------------------------------------");
//遍历链表
foreach(string s in list)
{
Console.WriteLine(s);
}
Console.WriteLine("--------------------------------------");
Console.WriteLine(list.Last.Previous.Value);
}
}
}
运行结果如下: