基于遗传算法的试题组卷(二)

实例讲解
在这里插入图片描述
在这里插入图片描述
一、准备工作
1、问题实体
问题实体包含编号、类型(类型即题型,分为五种:单选,多选,判断,填空,问答, 分别用1、2、3、4、5表示)、分数、难度系数、知识点。一道题至少有一个知识点,为简单易懂,知识点用List 表示(知识点编号集合)。
代码如下:

public class Problem 
{public Problem(){ID = 0;Type = 0;Score = 0;Difficulty = 0.00;Points = new List<int>();}public Problem(Problem p){this.ID = p.ID;this.Type = p.Type;this.Score = p.Score;this.Difficulty = p.Difficulty;this.Points = p.Points;}/// <summary>/// 编号/// </summary>public int ID { get; set; }/// <summary>/// 题型(1、2、3、4、5对应单选,多选,判断,填空,问答)/// </summary>public int Type { get; set; }/// <summary>/// 分数/// </summary>public int Score { get; set; }/// <summary>/// 难度系数/// </summary>public double Difficulty { get; set; }/// <summary>/// 知识点/// </summary>public List<int> Points { get; set; }} 

2、题库
为了简单,这里没有用数据库,题目信息临时创建,保存在内存中。因为对不同层次的考生一道题目在不同试卷中的分数可能不一样,因此题目分数一般是老师出卷时定的,不保存在题库中。且单选,多选,判断题每题分数应该相同,填空题一般根据空数来定分数,而问答题一般根据题目难度来定的,因此这里的单选、多选、判断分数相同,填空空数取1-4间的随机数,填空题分数即为空数,问答题即为该题难度系数*10取整。这里各种题型均为1000题,具体应用时改为数据库即可。
代码如下:

public class DB
{/// <summary>/// 题库/// </summary>public List<Problem> ProblemDB;public DB(){ProblemDB = new List<Problem>();Problem model;Random rand = new Random();List<int> Points;for (int i = 1; i <= 5000; i++){model = new Problem();model.ID = i;//试题难度系数取0.3到1之间的随机值model.Difficulty = rand.Next(30, 100) * 0.01;//单选题1分if (i < 1001){model.Type = 1;model.Score = 1;}//单选题2分if (i > 1000 && i < 2001){model.Type = 2;model.Score = 2;}//判断题2分if (i > 2000 && i < 3001){model.Type = 3;model.Score = 2;}//填空题1—4分if (i > 3000 && i < 4001){model.Type = 4;model.Score = rand.Next(1, 5);}//问答题分数为难度系数*10if (i > 4000 && i < 5001){model.Type = 5;model.Score = model.Difficulty > 0.3 ? (int)(double.Parse(model.Difficulty.ToString("f1")) * 10) : 3;}Points = new List<int>();//每题1到4个知识点int count = rand.Next(1, 5);for (int j = 0; j < count; j++){Points.Add(rand.Next(1, 100));}model.Points = Points;ProblemDB.Add(model);}}
} 

3、 试卷实体
试卷一般包含试卷编号,试卷名称,考试时间,难度系数,知识点分布,总题数, 总分数,各种题型所占比率等属性,这里为简单去掉了试卷名称跟考试时间。其中的知识点分布即老师出卷时选定本试卷要考查的知识点,这里用List(知识点编号集合)表示。
代码如下:

public class Paper
{/// <summary>/// 编号/// </summary>public int ID { get; set; }/// <summary>/// 总分/// </summary>public int TotalScore { get; set; }/// <summary>/// 难度系数/// </summary>public double Difficulty { get; set; }/// <summary>/// 知识点/// </summary>public List<int> Points { get; set; }/// <summary>/// 各种题型题数/// </summary>public int[] EachTypeCount { get; set; }
} 

二、开始遗传算法组卷之旅

  准备工作已经OK,下面就按上一篇介绍的流程进行操作啦!

1、产生初始种群
这里保证题数跟总分达到出卷要求即可,但为操作方便,这里再定义一个种群个体实体类Unit,包含编号、适应度、题数、总分、难度系数、知识点分布、包含的题目等信息(也可以修改一下试卷实体,用试卷实体表示):

public class Unit{public Unit(){ID = 0;AdaptationDegree = 0.00;KPCoverage = 0.00;ProblemList = new List<Problem>();}/// <summary>/// 编号/// </summary>public int ID { get; set; }/// <summary>/// 适应度/// </summary>public double AdaptationDegree { get; set; }/// <summary>/// 难度系数(本试卷所有题目分数*难度系数/总分)/// </summary>public double Difficulty{get{double diff = 0.00;ProblemList.ForEach(delegate(Problem p){diff += p.Difficulty * p.Score;});return diff / SumScore;}}/// <summary>/// 题目数量/// </summary>public int ProblemCount{get{return ProblemList.Count;}}/// <summary>/// 总分/// </summary>public int SumScore{get{int sum = 0;ProblemList.ForEach(delegate(Problem p){sum += p.Score;});return sum;}}/// <summary>/// 知识点分布/// </summary>public double KPCoverage { get; set; }/// <summary>/// 题目/// </summary>public List<Problem> ProblemList { get; set; }
}

下面即来产生初始种群,按个体数量,期望试卷知识点分布,各类型题目数等限制产生初始种群:

/// <summary>
/// 初始种群
/// </summary>
/// <param name="count">个体数量</param>
/// <param name="paper">期望试卷</param>
/// <param name="problemList">题库</param>
/// <returns>初始种群</returns>
public List<Unit> CSZQ(int count, Paper paper, List<Problem> problemList)
{List<Unit> unitList = new List<Unit>();int[] eachTypeCount = paper.EachTypeCount;Unit unit;Random rand = new Random();for (int i = 0; i < count; i++){unit = new Unit();unit.ID = i + 1;unit.AdaptationDegree = 0.00;//总分限制while (paper.TotalScore != unit.SumScore){unit.ProblemList.Clear();//各题型题目数量限制for (int j = 0; j < eachTypeCount.Length; j++){List<Problem> oneTypeProblem = problemList.Where(o => o.Type == (j + 1)).Where(p => IsContain(paper, p)).ToList();Problem temp = new Problem();for (int k = 0; k < eachTypeCount[j]; k++){//选择不重复的题目int index = rand.Next(0, oneTypeProblem.Count - k);unit.ProblemList.Add(oneTypeProblem[index]);temp = oneTypeProblem[oneTypeProblem.Count - 1 - k];oneTypeProblem[oneTypeProblem.Count - 1 - k] = oneTypeProblem[index];oneTypeProblem[index] = temp;}}}unitList.Add(unit);}//计算知识点覆盖率及适应度unitList = GetKPCoverage(unitList, paper);unitList = GetAdaptationDegree(unitList, paper, kpcoverage, difficulty);return unitList;
} 

2、计算种群个体的适应度
在上面的代码中最后调用了两个方法,GetKPCoverage跟GetAdaptationDegree,这两个方法分别是计算种群中个体的知识点覆盖率跟适应度。

关于种群个体的知识点覆盖率在上一篇文章中已经说过了(知识点分布用一个个体知识点的覆盖率来衡量,例如期望本试卷包含N个知识点,而一个个体中所有题目知识点的并集中包含M个(M<=N),则知识点的覆盖率为M/N。),具体算法如下:

/// <summary>/// 计算知识点覆盖率
/// </summary>
/// <param name="unitList">种群</param>
/// <param name="paper">期望试卷</param>
/// <returns>List</returns>
public List<Unit> GetKPCoverage(List<Unit> unitList, Paper paper)
{List<int> kp;for (int i = 0; i < unitList.Count; i++){kp = new List<int>();unitList[i].ProblemList.ForEach(delegate(Problem p){kp.AddRange(p.Points);});//个体所有题目知识点并集跟期望试卷知识点交集var common = kp.Intersect(paper.Points);unitList[i].KPCoverage = common.Count() * 1.00 / paper.Points.Count;}return unitList;
}

适应度方法的确定上一篇文章里已经说过,即:
f=1-(1-M/N)*f1-|EP-P|*f2

其中M/N为知识点覆盖率,EP为期望难度系数,P为种群个体难度系数,f1为知识点分布的权重,f2为难度系数所占权重。当f1=0时退化为只限制试题难度系数,当f2=0时退化为只限制知识点分布。 实现代码如下:

/// <summary>/// 计算种群适应度
/// </summary>
/// <param name="unitList">种群</param>
/// <param name="paper">期望试卷</param>
/// <param name="KPCoverage">知识点分布在适应度计算中所占权重</param>
/// <param name="Difficulty">试卷难度系数在适应度计算中所占权重</param>
/// <returns>List</returns>
public List<Unit> GetAdaptationDegree(List<Unit> unitList, Paper paper, double KPCoverage, double Difficulty)
{unitList = GetKPCoverage(unitList, paper);for (int i = 0; i < unitList.Count; i++){unitList[i].AdaptationDegree = 1 - (1 - unitList[i].KPCoverage) * KPCoverage - Math.Abs(unitList[i].Difficulty - paper.Difficulty) * Difficulty;}return unitList;
}

3、选择算子
这里选择算子采用轮盘赌选择法,即适应度越大的被选择到的概率越大。比如说种群中有20个个体,那么每个个体的适应度除以20个个体适应度的和得到的就是该个体的被选择的概率。轮盘赌选择时,每个个体类似于轮盘中的一小块扇形,扇形的大小与该个体被选择的概率成正比。那么,扇形越大的个体被选择的概率越大。这就是轮盘赌选择法。 算法实现代码如下:

/// <summary>
/// 选择算子(轮盘赌选择)
/// </summary>
/// <param name="unitList">种群</param>
/// <param name="count">选择次数</param>
/// <returns>进入下一代的种群</returns>
public List<Unit> Select(List<Unit> unitList, int count)
{List<Unit> selectedUnitList = new List<Unit>();//种群个体适应度和double AllAdaptationDegree = 0;unitList.ForEach(delegate(Unit u){AllAdaptationDegree += u.AdaptationDegree;});Random rand = new Random();while (selectedUnitList.Count != count){//选择一个0—1的随机数字double degree = 0.00;double randDegree = rand.Next(1, 100) * 0.01 * AllAdaptationDegree;//选择符合要求的个体for (int j = 0; j < unitList.Count; j++){degree += unitList[j].AdaptationDegree;if (degree >= randDegree){//不重复选择if (!selectedUnitList.Contains(unitList[j])){selectedUnitList.Add(unitList[j]);}break;}}}return selectedUnitList;
} 

4、交叉算子
交叉算子在上一篇也做了说明,写程序时为方便略做了一点更改,即把多点交叉改为单点交叉。在交叉过程在有几个地方需要注意,一是要保正总分不变,二是保证交叉后没有重复个体,算法实现如下:

   /// <summary>/// 交叉算子/// </summary>/// <param name="unitList">种群</param>/// <param name="count">交叉后产生的新种群个体数量</param>/// <param name="paper">期望试卷</param>/// <returns>List</returns>public List<Unit> Cross(List<Unit> unitList, int count, Paper paper){List<Unit> crossedUnitList = new List<Unit>();Random rand = new Random();while (crossedUnitList.Count != count){//随机选择两个个体int indexOne = rand.Next(0, unitList.Count);int indexTwo = rand.Next(0, unitList.Count);Unit unitOne;Unit unitTwo;if (indexOne != indexTwo){unitOne = unitList[indexOne];unitTwo = unitList[indexTwo];//随机选择一个交叉位置int crossPosition = rand.Next(0, unitOne.ProblemCount - 2);//保证交叉的题目分数合相同double scoreOne = unitOne.ProblemList[crossPosition].Score + unitOne.ProblemList[crossPosition + 1].Score;double scoreTwo = unitTwo.ProblemList[crossPosition].Score + unitTwo.ProblemList[crossPosition + 1].Score;if (scoreOne == scoreTwo){//两个新个体Unit unitNewOne = new Unit();unitNewOne.ProblemList.AddRange(unitOne.ProblemList);Unit unitNewTwo = new Unit();unitNewTwo.ProblemList.AddRange(unitTwo.ProblemList);//交换交叉位置后面两道题for (int i = crossPosition; i < crossPosition + 2; i++){unitNewOne.ProblemList[i] = new Problem(unitTwo.ProblemList[i]);unitNewTwo.ProblemList[i] = new Problem(unitOne.ProblemList[i]);}//添加到新种群集合中unitNewOne.ID = crossedUnitList.Count;unitNewTwo.ID = unitNewOne.ID + 1;if (crossedUnitList.Count < count){crossedUnitList.Add(unitNewOne);}if (crossedUnitList.Count < count){crossedUnitList.Add(unitNewTwo);}}}//过滤重复个体crossedUnitList = crossedUnitList.Distinct(new ProblemComparer()).ToList();}//计算知识点覆盖率及适应度crossedUnitList = GetKPCoverage(crossedUnitList, paper);crossedUnitList = GetAdaptationDegree(crossedUnitList, paper, kpcoverage, difficulty);return crossedUnitList;}

上面过滤重复个体中用到了ProblemComparer类,这是一个自定义的比较类,代码如下:

 public class ProblemComparer : IEqualityComparer<Unit>{public bool Equals(Unit x, Unit y){bool result = true;for (int i = 0; i < x.ProblemList.Count; i++){if (x.ProblemList[i].ID != y.ProblemList[i].ID){result = false;break;}}return result;}public int GetHashCode(Unit obj){return obj.ToString().GetHashCode();}
}

5、 变异算子
在变异过程中主要是要保证替换题目至少包含一个被替换题的有效知识点(期望试卷中也包含此知识点),并要类型相同,分数相同而题号不同。 算法实现代码如下:

/// <summary>
/// 变异算子
/// </summary>
/// <param name="unitList">种群</param>
/// <param name="problemList">题库</param>
/// <param name="paper">期望试卷</param>
/// <returns>List</returns>
public List<Unit> Change(List<Unit> unitList, List<Problem> problemList, Paper paper)
{Random rand = new Random();int index = 0;unitList.ForEach(delegate(Unit u){//随机选择一道题index = rand.Next(0, u.ProblemList.Count);Problem temp = u.ProblemList[index];//得到这道题的知识点Problem problem = new Problem();for (int i = 0; i < temp.Points.Count; i++){if (paper.Points.Contains(temp.Points[i])){problem.Points.Add(temp.Points[i]);}}//从数据库中选择包含此题有效知识点的同类型同分数不同题号试题var otherDB = from a in problemListwhere a.Points.Intersect(problem.Points).Count() > 0select a;List<Problem> smallDB = otherDB.Where(p => IsContain(paper, p)).Where(o => o.Score == temp.Score && o.Type == temp.Type && o.ID != temp.ID).ToList();//从符合要求的试题中随机选一题替换if (smallDB.Count > 0){int changeIndex = rand.Next(0, smallDB.Count);u.ProblemList[index] = smallDB[changeIndex];}});//计算知识点覆盖率跟适应度unitList = GetKPCoverage(unitList, paper);unitList = GetAdaptationDegree(unitList, paper, kpcoverage, difficulty);return unitList;
} 

遗传算法主要算法上面都已实现,现在就是调用了。调用过程按如下流程图进行:
在这里插入图片描述
这里初始种群大小设定为20,最大迭代次数为500,适应度为0.98,选择算子选择次数为10次,交叉算子产生的个体数量为20,期望试卷难度系数为0.72,总分为100分,各种题型题数为:20(单选), 5(多选), 10(判断), 7(填空), 5(问答),包含的知识点为:1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81。代码如下:

  /// <summary>/// 调用示例/// </summary>public void Show(){//题库DB db = new DB();//期望试卷Paper paper = new Paper(){ID = 1,TotalScore = 100,Difficulty = 0.72,Points = new List<int>() { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81 },EachTypeCount = new[] { 20, 5, 10, 7, 5 }};//迭代次数计数器int count = 1;//适应度期望值double expand = 0.98;//最大迭代次数int runCount = 500;//初始化种群List<Unit> unitList = CSZQ(20, paper, db.ProblemDB);Console.WriteLine("\n\n      -------遗传算法组卷系统(http://www.cnblogs.com/durongjian/)---------\n\n");Console.WriteLine("初始种群:");ShowUnit(unitList);Console.WriteLine("-----------------------迭代开始------------------------");//开始迭代while (!IsEnd(unitList, expand)){Console.WriteLine("在第 " + (count++) + " 代未得到结果");if (count > runCount){Console.WriteLine("计算 " + runCount + " 代仍没有结果,请重新设计条件!");break;}//选择unitList = Select(unitList, 10);//交叉unitList = Cross(unitList, 20, paper);//是否可以结束(有符合要求试卷即可结束)if (IsEnd(unitList, expand)){break;}//变异unitList = Change(unitList, db.ProblemDB, paper);}if (count <= runCount){Console.WriteLine("在第 " + count + " 代得到结果,结果为:\n");Console.WriteLine("期望试卷难度:" + paper.Difficulty + "\n");ShowResult(unitList, expand);}} 
最后在控制台中调用此方法即可。 

7、其他辅助方法
在上面的代码中还调用了几个辅助方法,下面一并给出:

#region 是否达到目标/// <summary>/// 是否达到目标/// </summary>/// <param name="unitList">种群</param>/// <param name="endcondition">结束条件(适应度要求)</param>/// <returns>bool</returns>public bool IsEnd(List<Unit> unitList, double endcondition){if (unitList.Count > 0){for (int i = 0; i < unitList.Count; i++){if (unitList[i].AdaptationDegree >= endcondition){return true;}}}return false;}#endregion#region 显示结果/// <summary>/// 显示结果/// </summary>/// <param name="unitList">种群</param>/// <param name="expand">期望适应度</param>public void ShowResult(List<Unit> unitList, double expand){unitList.OrderBy(o => o.ID).ToList().ForEach(delegate(Unit u){if (u.AdaptationDegree >= expand){Console.WriteLine("第" + u.ID + "套:");Console.WriteLine("题目数量\t知识点分布\t难度系数\t适应度");Console.WriteLine(u.ProblemCount + "\t\t" + u.KPCoverage.ToString("f2") + "\t\t" + u.Difficulty.ToString("f2") + "\t\t" + u.AdaptationDegree.ToString("f2")+"\n\n");}});}#endregion#region 显示种群个体题目编号/// <summary>/// 显示种群个体题目编号/// </summary>/// <param name="u">种群个体</param>public void ShowUnit(Unit u){Console.WriteLine("编号\t知识点分布\t难度系数");Console.WriteLine(u.ID + "\t" + u.KPCoverage.ToString("f2") + "\t\t" + u.Difficulty.ToString("f2"));u.ProblemList.ForEach(delegate(Problem p){Console.Write(p.ID + "\t");});Console.WriteLine();}#endregion 
#region 题目知识点是否符合试卷要求
/// <summary>
/// 题目知识点是否符合试卷要求
/// </summary>
/// <param name="paper">期望试卷</param>
/// <param name="problem">一首试题</param>
/// <returns>bool</returns>
private bool IsContain(Paper paper, Problem problem)
{for (int i = 0; i < problem.Points.Count; i++){if (paper.Points.Contains(problem.Points[i])){return true;}}return false;
}
#endregion

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/20555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL】触发器 (十二)

🚗MySQL学习第十二站~ 🚩本文已收录至专栏:MySQL通关路 ❤️文末附全文思维导图,感谢各位点赞收藏支持~ 一.引入 触发器是与表有关的数据库对象,作用在insert/update/delete语句执行之前(BEFORE)或之后(AFTER),自动触发并执行触发器中定义的SQL语句集合。它可以协助应…

解决Win11右键菜单问题

✅作者简介&#xff1a;大家好&#xff0c;我是Cisyam&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Cisyam-Shark的博客 &#x1f49e;当前专栏&#xff1a; 程序日常 ✨特色专栏&…

【MyBatis】 框架原理

目录 10.3【MyBatis】 框架原理 10.3.1 【MyBatis】 整体架构 10.3.2 【MyBatis】 运行原理 10.4 【MyBatis】 核心组件的生命周期 10.4.1 SqlSessionFactoryBuilder 10.4.2 SqlSessionFactory 10.4.3 SqlSession 10.4.4 Mapper Instances 与 Hibernate 框架相比&#…

【HAL库】STM32CubeMX开发----STM32F407----LAN8720A----移植FreeModbus实现ModbusTCP

前言 本次实验以 STM32F407VET6 芯片为MCU&#xff0c;使用 25MHz 外部时钟源。 以太网PHY层芯片为 LAN8720A&#xff0c;移植FreeModbus实现ModbusTCP网口通信。 具体内容参考文章&#xff1a;【HAL库】STM32CubeMX开发----STM32F407----ETHLAN8720ALWIP----ping通 本次移植…

零基础强化学习入门分享

&#xff08;一&#xff09;前言&#xff1a;强化学习入门顺序。 以前主要学习硬件PCB单片机等知识&#xff0c;后来接触的项目也大多与电气相关&#xff0c;从一窍不通到稍微找到点门道&#xff0c;中间走过不少弯路&#xff0c;误打误撞中&#xff0c;也留下了一些经验。 我的…

微服务——elasticsearch

初识ES——什么是elasticsearch elasticsearch的发展 初识ES——正向索引和倒排索引 初识ES——es与mysql的概念对比 类比到mysql中是表结构约束 概念对比 初始ES——安装es和kibana 1.部署单点es 1.1创建网络 要安装es容器和kibana容器并让他们之间相连&#xff0c;这里…

RabbitMQ-API

这里写目录标题 Hello word 模式添加依赖生产者消费者获取信道工具类 Work Queues模式消费者代码 C1开启多线程运行启动 消费者代码 C2生产者代码 消息应答自动应答消息应答的方法Multiple 的解释消息自动重新入队消息手动应答代码消费者API 队列持久化消息持久化不公平分发消息…

redis 高级篇 redis 源码的读取分析

一 redis源码分析 1.1 源码分析 1每一个kv键值对应有一个dictEntry。 2.底层数据结构

mysql数据库迁移

目录 背景迁移数据库 背景 公司有个项目&#xff0c;刚开始数据量不是大的时候&#xff0c;数据库和服务上的所有应用数据都放在一个旧小盘中&#xff0c;随着项目数据的增长&#xff0c;旧的磁盘被占满了&#xff0c;导致系统无法写入数据&#xff0c;我和同事排查了很长时间…

C++运算符重载详解(赋值、流插入流提取、前置后置++、取地址)

C运算符重载详解 基本介绍运算符重载案列1. 赋值运算符重载2. 前置和后置重载3. cout&#xff0c;cin(流插入&#xff0c;流提取重载)4. 取地址重载 基本介绍 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊函数名的函数&#xff0c;也具有其 返回值…

生态共建丨YashanDB与构力科技完成兼容互认证

近日&#xff0c;深圳计算科学研究院崖山数据库系统YashanDB V22.2与北京构力科技有限公司BIMBase云平台完成兼容性互认证。经严格测试&#xff0c;双方产品完全兼容、运行稳定。 崖山数据库系统YashanDB是深算院自主研发设计的新型数据库系统&#xff0c;融入原创理论&#xf…

CAD随机球体颗粒过渡区3D插件

插件介绍 CAD随机球体颗粒&过渡区3D插件可用于在AutoCAD软件内生成随机分布的球体及球体外侧过渡区部件&#xff0c;适用于科研绘图、有限元建模如混凝土细观、颗粒增强复合材料、随机三维骨料及过渡区等方面的应用。 插件可指定的参数有模型的长、宽、高&#xff1b;球…

SpringBoot单元测试

目录 1.什么是单元测试? 2.单元测试有哪些好处? 3.Spring Boot单元测试使⽤ 单元测试的实现步骤 1. ⽣成单元测试类 2. 添加单元测试代码 2.1 .添加Spring Boot框架测试注解:SpringBootTest 2.2 添加单元测试业务逻辑 简单的断⾔说明 1.什么是单元测试? 单元测试(un…

RPC框架引入zookeeper服务注册与服务发现

Zookeeper概念及其作用 ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&#xff0c;是大数据生态中的重要组件。它是集群的管理者&#xff0c;监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理…

使用 GitHub Copilot 进行 Prompt Engineering 的初学者指南(译)

文章目录 什么是 GitHub Copilot ?GitHub Copilot 可以自己编码吗&#xff1f;GitHub Copilot 的底层是如何工作的&#xff1f;什么是 prompt engineering?这是 prompt engineering 的另一个例子 使用 GitHub Copilot 进行 prompt engineering 的最佳实践提供高级上下文&…

Springboot -- 按照模板生成docx、pdf文件,docx转pdf格式

使用 poi-tl 根据模板生成 word 文件。 使用 xdocreport 将 docx 文件转换为 pdf 文件。 xdocreport 也支持根据模板导出 word &#xff0c;但是 poi-tl 的功能更齐全&#xff0c;操作更简单&#xff0c;文档清晰。 poi-tl 、xdocreport 内部均依赖了 poi &#xff0c;要注意两…

uniapp 全局数据(globalData)的设置,获取,更改

globalData&#xff0c;这是一种简单的全局变量机制。这套机制在uni-app里也可以使用&#xff0c;并且全端通用 因为uniapp基本上都是将页面&#xff0c;或者页面中相同的部分&#xff0c;进行组件化&#xff0c;所以会存在父&#xff0c;子&#xff0c;&#xff08;子&#xf…

【数据挖掘竞赛】——科大讯飞:锂离子电池生产参数调控及生产温度预测挑战赛

🤵‍♂️ 个人主页:@Lingxw_w的个人主页 ✍🏻作者简介:计算机科学与技术研究生在读 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ ​ 【科大讯飞】报名链接:https://challenge.xfyun.cn?invitaC…

在windows下安装ruby使用gem

在windows下安装ruby使用gem 1.下载安装ruby环境2.使用gem3.gem换源 1.下载安装ruby环境 ruby下载地址 选择合适的版本进行下载和安装&#xff1a; 在安装的时候&#xff0c;请勾选Add Ruby executables to your PATH这个选项&#xff0c;添加环境变量&#xff1a; 安装Ruby成…

【Ansible 的脚本 --- playbook 剧本】

目录 一、playbook 剧本介绍二、示例1、运行playbook2、定义、引用变量 三、使用playbook部署lnmp集群 一、playbook 剧本介绍 playbooks 本身由以下各部分组成 &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在…