背景需求——幼小衔接适应
疫情危机,孩子们哪里也不敢去。为了丰富幼儿的寒假生活。搭档程老师想给孩子布置一些打卡任务,运动、绘画、写字等,她找到网上一份20以内的加减法7页纸的题目想发给家长打印,但无法下载(收费 )。我想既然我会一点python,自己批量一些题应该不难吧。
出现问题——批量加减法有重复
加减法练习,包括了前书写(名字、日期)和思维练习(数字、计算),有助于大班孩子们感知一年级的题型样式,逐步适应小学数学模式。因此我尝试拷贝、修改以前下载的加减法python代码,顺利完成了Word模板的填写。但是,前期孩子们说“有题目是一样的”的现象非常明显(相同的题目相邻出现) ——本次批量了360题,用Excel查找重复值后,只留下了215条不重复的,41%的题目都是重复的。为了删除重复题,又费了不少时间。
解决途径——求教IT高手
IT网管员马先生提供了技术支持,经过三轮测试,制作了一个代码行数较少的“20以内加减法不重复”的代码,测试后的确实现了预期需求
一、代码(简易版)
# -*- coding: utf-8 -*- """ @author: 马清新 @file: 马清新注释版 不重复的20以内加减法(最多190题).py @time: 2022/1/19 8:42 """ import random # regList用于存储合规的加减法表达式(正确列式) regList = [] # answer用于存储合规的加减法表达式(正确答案) answer = [] maxNum = int(input('请输入加法和最大值(10以内 20以内'))#输入最大值 regnum = int(input('请输入出题数量(20以内取值范围小于等于190题)'))#输入题目数量 # 加减法 i = regnum # i=出题数量 循环记数使用 while i > 0: #当数量大于0,执行 try: #try……except含义:try没有异常时,处理器不执行, # regStr = '' #把整数算式转换成字符串使用的,初始情况下让它为空比较保险 # 随机 要求和值范围内的 随机数 a = random.randint(1,maxNum) # 随机 要求和值范围内的随机数,要求两随机数和不得大于maxNum b = random.randint(1,(maxNum-a)) # 比较两各随机数大小,如a<b使用加法,a>b则使用减法,c是记录加减法的答案 if a <= b: #如果第1个数小于等于第2个数 c= a + b #第3个数=第1个数+第2个数 # 将加减法表达式转换为字符串模式 str regStr = str(f'{a} + {b} ={c}') # 将加减法表达式含答案转换为字符串模式 answerStr = str(f'{a} + {b} = ')#打印结果“第1个数+第2个数” answer是要被打印的,所以C为空 else: c = a - b #如果第3个数=第1个数-第2个数(如果第1个数大于第2个数) regStr = str(f'{a} - {b} ={c}') answerStr = str(f'{a} - {b} = ')#打印结果“第1个数-第2个数” # 利用if not in 去重,符合去重条件的保存,不符合的从头执行。 if regStr not in regList:#如果整数转字符串的题目 不在regList的列表内 # append 是列表的方法,是在列表的结尾添加新的元素,元素就是咱们符合要求的算式 regList.append(regStr)#regList是不含答案的列表,每次出题学生得到的是没答案的算式。 answer.append(answerStr)#这个是带了答案的符合要求算式的列表,老师手上的是有答案的,本题教师需要的没有答案的,所以C为空。 # regList和answer都是空列表,为存放找到算式预留的, # 两个唯一的区别就是一个有答案给老师answerStr,一个没答案给学生regStr i -= 1 #找到了符合要求的算式,见19行题目数 需要减掉1,因为i的初始值是需要得到算式的数量,每找到一个就减一个,直到0 else: continue # 随机过程中可能会出现随机数报错 # 例如 a随机为19,b的随机范围变成rangeint(1,1)这种情况系统会报错,需要进行处理 except ValueError: # try……except含义:try有异常时, 执行except搜索异常处理器,找异常声明,没有找到,异常被保存。 # 打印错误 打印ValueError的字样 print(ValueError) # 继续从头执行程序 continue # 打印带答案的算术加减法 for _ in answer :#最后得到的符合不重复算式的列表answer, print(_) #print(_)循环打印出来验证一下 # 确认加减法出题量 验证列表的长度,验证一下总共是否与需求的算式数量一致NUM print(len(answer)) # 这里的_是一种省略变量的方法,就是系统随便分配一个变量,用完就回收了,免得再定义一个了 可以用i 或者j这些变量去代替。这里的_是一种省略变量的方法,就是系统随便分配一个变量,用完就回收了,免得再定义一个了 可以用i 或者j这些变量去代替。 # 1月19日版本 # 保存为TXT文件(在默认打开文件夹下,手动拷贝到Word里 #str_title = '2.txt' # 保存文件名 #with open('2.txt','w') as f:# 打开TXT文件 # for a in answer:# #循环查找答案的内容 # f.write(str(a)+'\n')# 写入答案内容并回车 #f.close()# #关闭TXT # 2月4日版本 保存带数字提示的题目,如5以内加减法题(8题) 但是输入的题目超过最大不重复的题目数量后,就会报错,所以这段代码废弃。 str_title = '%d以内的加减法题(共%d题).txt' % (maxNum, len(answer)) # 保存带数字提示的题目 with open(str_title,'w') as f:# 打开TXT文件 for a in answer:# #循环查找答案的内容 f.write(str(a)+'\n')# 写入答案内容并回车 f.close()# #关闭TXT
作者后续优化思路:
第一次设计的程序,是用足够多的异常强逼出最后不重复的算式小,要的和小还行,超过100效率就低了。所以20以内题目超过190题就报错,我想了好一阵如何去除报错问题。
昨天那个代码,把数字和加减法都用随机的方式生成,目的是保证生成足够多的算式就可以。想去掉重复,最好是做题库,然后随机索引去抽题,可以分开加减法。其实不用random做,问题也许更简单,那个重复1000次报错,其实就是算法本身缺陷造成的。今天我利用随机数比大小去做去重,但是发现这个只是正常的操作方法,算法上有漏洞,
拿20以内的加减法来说,去掉减法答案为0的题,算法如下,建立一个整数列表 范围 0至19,这样可以保证列表索引和列表元素一致.
然后设置双层循环次数,第一层从索引1开始,到索引20/2,底层索引刚从1到20-1(1用i,做变量),这样每个循环得到一个加法算式和减法算式成对出现,这样当顶层循环到20/2的位置的时候,所有非重复的算式加减法都出来了
可以根据自己的需要建立加法算式列表和减法算式列表,当需要抽题的时候,直接random一下就可以了。这样就不存在异常的情况了
最终版算法,合格靠谱了,算是正轨算法吧(加了最大不重复算式统计值)
一、代码(正式版 以此为准)
# -*- coding: utf-8 -*-
"""
@author: 马清新
@file: 马清新 20以内加减法(最大不重复算式值).py
@time: 2022/1/20 20:15
# 特别说明
1.根据预测试:10以内不重复132题,20以内不重复的462,50以内2652 100以内10302
样式1:如果20以内的题目数量输入了1000题,但它最终只会出现380题(共生成不重复380,最大不重复380)
样式2:如果50以内输入1000题,它最终会出现1000题(共生成不重复1000),但实际最多可以出现的1824题(最大不重复2450)
2.本次的最大值和题数可以无限大,但是考虑到电脑算力和生成时长,建议不要超过1000以内(999000题).
3.X以内 两个数加减法(X+Y= X-Y= )的最大不重复题目数量:
X以内 加法题 减法题 加减法乱序题 排除答案0
5 21 21 42 36
10 66 66 132 121
20 231 231 462 441
50 1326 1326 2652 2601
100 5151 5151 10302 10201
"""
import random
sumMax = int(input('请输入算式最大和:'))
regNum = int(input('请输入需要生成算式的数量:'))
# 生成1个列表,列表从0开始,到算术最大和结束,因为range函数包左不包右,因此如果要包括算式最大和,必须+1
# range函数从0开始,这样列表元素和列表索引一致,减轻算法的难度
numList = [x for x in range(0,sumMax+1)]
# resultList列表用于保存最后最大数量的合规算术式
resultList = []
for x in numList[0:]:
# 从列表第x个元素开始到列表最后一个元素进行循环遍历
for y in numList[x:]:
# 加和减 列表元素开始时存在两个元素相等的情况,由于加法交换律会产生重复,所以单独进行区分
if (x == y) and (x + y <= sumMax)and (y != 0): # X或Y两者一个或者两个都不能0。没有0+0,0-0
tempStr = str(x) + ' + ' + str(y) + ' = '
resultList.append((tempStr, (x+y)))
tempStr = str(x) + ' - ' + str(y) + ' = '
resultList.append((tempStr, (x-y)))
#加和减 查找 x + y < 算式最大和的加减法,此处考虑加法交换律,减法中去除了相减为0的情况,因为此处y>x
elif x + y <= sumMax and (y != 0):# 第一位或者第二位都不为0,也就是没有
tempStr = str(x) + ' + ' + str(y) + ' = '
resultList.append((tempStr, (x+y)))
tempStr = str(y) + ' + ' + str(x) + ' = '
resultList.append((tempStr, (x+y)))
tempStr = str(y) + ' - ' + str(x) + ' = '
resultList.append((tempStr, (y-x)))
# 考虑循环后期,x+y会打印算式要求的最大和,但是减法符合算式要求,处于严谨的考虑没有使用else
# 减法 此处可以考虑直接使用else
elif y - x >= 0 and y != 0: # y可能等于x ,答案为0,但没有0-0
tempStr = str(y) + ' - ' + str(x) + ' = '
resultList.append((tempStr, (y-x)))
elif y - x == 0 :#等数 相加 相减等于0,不需要的话,此段注释掉
tempStr = str(y) + ' + ' + str(x) + ' = '#减法类型3 y-x=0
resultList.append((tempStr, (y+x)))# 带答案的题目,如0+0=0,
tempStr = str(y) + ' - ' + str(x) + ' = '#减法类型3 y-x=0
resultList.append((tempStr, (y-x)))# 带答案的题目,如0-0=0,
# 建立最终符合最终要求的算式列表9
selectList = []
if regNum > len(resultList):#输入题数大于实际需求,就用shuffle洗牌,
print(f'您的需求大于最大算式生成数量!最大生成算式数量为{len(resultList)}')
i = len(resultList)
for _ in resultList:
selectList.append(_)
random.shuffle(selectList) #shuffle 洗牌算法,把列表所有元素打乱,随机排列
for _ in selectList:
# 可选打印带答案的和不带答案啊
print(_[0])# 不带答案
# print(f'{_[0]}{_[1]}')# 带答案
else:#输入题数小于实际需求,代码自动随机抽取,不会排序,
i = regNum
selectList = random.sample(resultList,i)
for _ in selectList:
# 可选打印带答案的和不带答案啊
print(_[0])# 不带答案
# print(f'{_[0]}{_[1]}')# 带答案
# 验证生成算式数量
print(f'共生成不重复的算式{len(selectList)}')
print(f'最大不重复的算式{len(resultList)}')
# 保存为TXT文件(在默认打开文件夹下,手动拷贝到Word里1
# str_title = '2.txt' # 保存文件名60
# with open('2.txt','w') as f:# 打开TXT文件
# for a in selectList:# #循环查找答案的内容8
# # f.write(str(a[0])+'\n')# 写入答案内容并回车 a[0]没有答案
# f.write(str(a[0])+'\n')#写入答案内容并回车 a[1]有答案
# f.close()# #关闭TXT、
# 2月4日修改TXT文件名称
str_title = '%d以内的加减法题(共%d题).txt' % (sumMax, len(resultList)) # 保存带数字提示的题目
with open(str_title,'w') as f:# 打开TXT文件
for a in selectList:# #循环查找答案的内容
f.write(str(a[0])+'\n')# 不带答案
# f.write(str(a[1])+'\n')#只有答案
# f.write(str(a[0])+str(a[1])+'\n')#有题目有答案 TXT里面是题目+答案,终端显示题目 无答案,因为上面选了(0)
f.close()# #关闭TXT
二、代码运行
(一 )运行
(二)运行 第一个问题,输入“X以内加减法”中的X数字20
(三)运行第二个问题输入任意数字
(四)VS界面结果
(五)TXT结果
打印模板——Word打印模板制作(后期尝试能直接生成Word模板,现在先手动)
1、题目样张
2、统一抬头(在页眉里设置)
3、作业页码(插入页码)
4、把TXT的数字批量拷贝到Word里
5、制作四列分栏
6、字体变大
7、添加外框
8、462题可以布满15张差一些
教学反思——抓牢基础,万变不离
感谢马先生写的代码,解决了我在批量加减法题中的题目重复问题,从实际需求中去学习如何解读代码内容,让记忆中的基础知识被唤醒,真正地理解其实用性。从直观效果中加深记忆和理解。鸣谢大师!
这是阿夏第7个实际运用到幼儿园教学中的Python自动化案例(教学类-06),希望能通过借鉴、实验、修改,将Python运用到幼儿园办公工作和幼儿教学中,提高工作效率,推动幼儿个性化学习和层次性学习成效。