13. 第十三章 案例研究-选择数据结构

13. 案例研究-选择数据结构

到这里尼应该已经学会了Python的核心数据结构, 也见过了一些使用它们的算法.
如果你想要更多地了解算个发可以阅读第21.
本章配合联系介绍一个案例分析, 帮你思考如何选择数据结构并如何使用它们.
13.1 单词频率分析
1. 练习1
编写一个程序, 读入一个文件, 将每行内容拆解为单词, 剥去单词周围的空白字符和标点, 并转换为小写.
提示: string模块提供了whitespace, 包括空格, 制表符, 换行符等;它也提供了punctuation, 包含了所有的标点字符.使用的文件为: https://raw.githubusercontent.com/AllenDowney/ThinkPython2/master/code/emma.txt
>>> import string
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>> string.whitespace
'\t\n\x0b\x0c\r '
另外也可以考虑字符串方法, strip, replace和translate.
translate方法: 返回一个可用于 str.translate()的转换表.
如果只有一个参数, 它必须是将Unicode序数(整数)或字符映射到Unicode序数, 字符串或None的字典.
然后, 字符键将转换为序数.
如果有两个参数, 它们必须是长度相等的字符串, 并且在生成的字典中, 
x中的每个字符都将映射到y中相同位置的字符.
如果有第三个参数, 它必须是一个字符串, 其字符将在结果中映射到 None.
# string模式使用
import string# 提供一个参数是, 参数必须是字典, 键的长度必须是1, 还是Unicode的字符.
d1 = str.maketrans({'a': 'v1', 'b': 'v2'}) 
print(d1)  # {97: 'v1', 98: 'v2'}# 提供两个参数, 参数的长度必须相等, x中的每个字符都将映射到y中相同位置的字符.
special_characters = string.punctuationd2 = str.maketrans(special_characters, '|'*32)
# 字符对于的unicode编码十进制. 124是'|'
print(d2)  # {33: 124, 34: 124, 35: 124, 36: 124, 37: 124, 38: 124, 39: 124 ...}# 第三个参数的值作为键, None作为值.
d3 = str.maketrans(special_characters, '|'*32, 'asd')
print(d3)  # {33: 124, 34: 124, 35: 124, 36: 124, 37: 124, 38: 124, 39: 124 ... 97: None, 115: None, 100: None}
文件中使用-拼接单词, 将-替换换空格, 字符串再按空格切分为列表, 最后对单词前后的符号做处理.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def read_file(file_name):""":param file_name: 文件的路径:return: 直方图"""words_dict = dict()file_data = open(file_name, encoding='utf8')for line in file_data:# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率words_dict: dictwords_dict[lower_word] = words_dict.get(lower_word, 0) + 1return words_dictres_words_dict = read_file('emma.txt')
# print(res_words_dict)
print(len(res_words_dict))  # 7530
存在这样的单词与单词组合或数字:
网站: http://pglaf.org/donate'
邮箱: business@pglaf.org
标记: 1.e.2, 0.zip
数字: 90
缩写单词: sister's, taylor's 只有这个是正常的.
往下写练习2去除掉文章的开头结尾读取正文部分, 上面几种除了缩写单词外都会消失...
2. 练习2
去往古腾堡工程(Project Gutenberg, http://www.gutenberg.org)
并下载你最喜欢的无版权的纯文本文档.修改前一个练习中的程序, 改为从你下载的书籍中读取内容, 
跳过文件开头的信息部分, 并和前面一样将文本处理成单词. (去除开头与结尾, 读取文件的正文部分.)接着修改程序, 计算书中出现的全部单词的总数, 以及每个单词使用的次数.(下面没必要去搞...)
打印书中使用的不同单词的个数. 比较不同的时代, 不同的作者的不同书籍.
哪一个作者使用的词汇最广泛? 
*** START OF THIS PROJECT GUTENBERG EBOOK EMMA ***
正文...
*** END OF THIS PROJECT GUTENBERG EBOOK EMMA ***
使用字符串的startwith方法, 开头结尾.
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def read_file(file_name):""":param file_name: 文件的路径:return: 直方图"""words_dict = dict()file_data = open(file_name, encoding='utf8')# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率words_dict: dictwords_dict[lower_word] = words_dict.get(lower_word, 0) + 1return words_dictdef skip_header(file_obj):""":param file_obj: 文件对象:return: None读取文件对象, 读取到 *** START OF THIS PROJECT GUTENBERG EBOOK EMMA *** 这一行则停止"""for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):breakres_words_dict = read_file('emma.txt')
# print(res_words_dict)
print('单词数量:', len(res_words_dict))  # 7212
print('单词总数:', sum(res_words_dict.values()))  # 161057
3. 练习3
修改前一个练习中的程序, 计算书中使用频率最高的20个单词.
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def read_file(file_name):""":param file_name: 文件的路径:return: 直方图"""words_dict = dict()file_data = open(file_name, encoding='utf8')# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率words_dict: dictwords_dict[lower_word] = words_dict.get(lower_word, 0) + 1return words_dictdef skip_header(file_obj):""":param file_obj: 文件对象:return: None读取文件对象, 读取到 *** START OF THIS PROJECT GUTENBERG EBOOK EMMA *** 这一行则停止"""for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):break# 频率排序
def frequency_sorting(words_dict):words_list = list()for k, v in words_dict.items():# 组织成元组列表words_list.append((v, k))# 列表的按每个元素的第一个元素进行排序, 降序words_list.sort(reverse=True)# 返回前20个return words_list[:20]res_words_dict = read_file('emma.txt')
for val, key in frequency_sorting(res_words_dict):print(key, val)
4. 练习4
修改前面的程序, 读入一个单词表(参见9.1), 并打印出书中所有不在单词表之中的单词.
(下面的不要理会)
这其中有多少是拼写错误? 有多少是因该出现在单词表中的常用单词? 有多少是正确冷僻的单词?
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def read_file(file_name):""":param file_name: 文件的路径:return: 直方图"""hist = dict()file_data = open(file_name, encoding='utf8')# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率hist: dicthist[lower_word] = hist.get(lower_word, 0) + 1return histdef skip_header(file_obj):""":param file_obj: 文件对象:return: None读取文件对象, 读取到 *** START OF THIS PROJECT GUTENBERG EBOOK EMMA *** 这一行则停止"""for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):breakdef make_words_dict(file_name):words_dict = dict()fin = open(file_name, encoding='utf8')for line in fin:# 去除结尾\nword = line.strip()words_dict[word] = ''return words_dictdef difference():res_hist = read_file('emma.txt')res_words_dict = make_words_dict('words.txt')# 判断存在的单词与不存在额单词not_exist_words_list = list()for word in res_hist:if word not in res_words_dict:not_exist_words_list.append(word)print('存在的单词有', len(res_hist) - len(not_exist_words_list), '个.')print('不存在的单词有', len(not_exist_words_list), '个.')difference()
13.2 随机数
给定相同的输入, 大部分计算机程序每次运行都会生产相同的输出, 所以它们被认为是有确定性的.
确定性通常是件好事, 因为我们希望相同的计算能有相同的结果.
但对某些特别的应用, 我们希望计算机是不可预测的. 游戏是一个明显的例子, 但还有更多类似的例子.让程序变得真正地不确定很难, 但也有办法让它至少看起来是不确定的. 一种办法是使用算法来生成'伪随机数'.
伪随机数并不是真正随机的, 因为它们是通过一个确定性的算法生产的,
但若只是输出的数字的话, 几乎不可能看出来和随机数有什么区别.模块random提供了用于生成伪随机数的函数(接下来我直接简单地将它称为'随机数').
函数random返回一个从0.01.0之间的随机浮点(包括0.0, 但不包括1.0).
每当调用random时, 会得到一个很长的随机数序列中的下一个数.
运行下面的循环, 可以看到一个样本:
import random
for i in range(10):x = random.random()print(x)
函数randint接收参数low和high, 并返回low和high之间(两则都包含)的一个整数.
>>> random.randint(5, 10)
5
>>> random.randint(5, 10)
9
要从序列中随机选择一个元素, 可以使用choice:
>>> t = [1, 2, 3]
>>> random.choice(t)
2
>>> random.choice(t)
3
random模块还提供了可以从各种连续分布序列中生成随机数的函数,
包括高斯分布, 指数分布, y分布以及其他几种.
1. 练习5
编写一个函数choose_from_hist, 接受一个11.1节所定义的直方图作为参数, 
并从这个直方图中, 按照频率的大小, 成比例地随机返回一个值. 
例如, 下面这个直方图:
>>> t = ['a', 'a', 'b']
>>> hist = histogram(t)
{'a': 2, 'b': 1}
你的函数因该是以2/3地概率返回'a', 1/3的概率返回'b'.
import randomdef choose_from_hist(hist_dict):frequency_list = list()# 遍历键值对for key, val in hist_dict.items():# 列表添加val个键for i in range(val):frequency_list.append(key)random_res = random.choice(frequency_list)return random_resfor v in range(3):histogram_dict = {'a': 2, 'b': 1}res = choose_from_hist(histogram_dict)print(res)
13.3 单词直方图
在继续阅读之前你应当尝试前面的练习.
你可以从↓下载我的解答.
https://github.com/AllenDowney/ThinkPython2/tree/master/code/analyze_book1.py 
下面是一个读取文件中单词构造直方图的例子:
import stringdef process_file(filename):hist = dict()fp = open(filename)for line in fp:process_line(line, hist)return histdef process_line(line, hist):line = line.replace('-', ' ')for word in line.split():word = word.strip(string.punctuaion + string.whitespace)word = word.lower()hist[word] = hist.get(word, 0) + 1hist = process_file('emma.txt')
这个程序读入emma.txt, 其内容是简·奥斯丁的<<爱玛>>的文本.
process_file循环遍历文件中的每一行, 每次将一行传递给process_line函数, 直方图hist用作累加器.
process_line使用字符串方法reolace将'-'符号替换我i空额, 再使用split将各行文本拆分成一个字符串列表.
它遍历单词列表, 使用strip和lower去掉标点符号并转换为小写.
(我们说'转换', 只是简称, 记住字符串是不可变的, 所有strip和lower这样的方法返回的是新字符串.)
最后, process_line通过创建新项或者增加有项的值来更新直方图.
要计算文件中单词的总数, 我们可以累加直方图中的频率:
def total_words(hist):return sum(hist.values())
不同单词的个数, 就是字典里的元素数量:
def different_words(hist):return len(hist)
下面是打印结果的代码:
print('Total number of words:', total_words(hist))
print('Number of different words', different_words(hist))
以及结果:
Total number of words: 164120
Number of different words 8904
import stringdef process_file(filename):hist = dict()fp = open(filename, encoding='utf8')for line in fp:process_line(line, hist)return histdef process_line(line, hist):line = line.replace('-', ' ')for word in line.split():word = word.strip(string.punctuation + string.whitespace)word = word.lower()hist[word] = hist.get(word, 0) + 1hist = process_file('emma.txt')def total_words(hist):return sum(hist.values())def different_words(hist):return len(hist)# 单词总数
print('Total number of words:', total_words(hist))
# 不同单词的数量
print('Number of different words', different_words(hist))
13.4 最常见的单词
要寻找最常用的单词, 我们生成一个元组的列表, 其中每个元组包括一个单词及其频率, 并对其进行排序.
下面的函数接受一个直方图, 并返回'单词-频率'元组的列表:
def most_common(hist):t = []for key, value in hist.items():t.append((value, key))t.sort(reverse=True)return t
在每个元组中, 频率先出现, 所有结果列表按频率排序, 下面的循环打印出最常用的10个单词:
t = most_common(hist)print('The most common word are:')for freq, word in t[:10]:print(word, freq, sep='\t')
这里我使用关键字sep通知print去使用制表符最为分隔符, 而不使用空格.
于是第二列可以对其排序. 下面是<<爱玛>>的结果:
The most common word are:
to	5242
the	5205
and	4897
of	4295
i	3191
a	3130
it	2529
her	2483
was	2400
she	2364
这段代码可以使用sort函数的key参数进行简化.
如果你有兴趣, 可以读一下相关文章: http://wiki.python.org/moin/HowTo/Sorting.
list.sort(key=None, reverse=False)
key: 自定义排序的方式的键.
reverse控制是按升序还是降序排.
list.sort(key=lambda x1: x1[1])
自动遍历列表, 将遍历的元素作为参数给x1, 再出去参数的第二个元素赋值给key.
# 完整代码
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def read_file(file_name):""":param file_name: 文件的路径:return: 直方图"""hist = dict()file_data = open(file_name, encoding='utf8')# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率hist: dicthist[lower_word] = hist.get(lower_word, 0) + 1return histdef skip_header(file_obj):""":param file_obj: 文件对象:return: None读取文件对象, 读取到 *** START OF THIS PROJECT GUTENBERG EBOOK EMMA *** 这一行则停止"""for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):breakdef most_common(hist):t = []for key, value in hist.items():t.append((value, key))t.sort(reverse=True)return thist = read_file('emma.txt')
t = most_common(hist)print('The most common word are:')for freq, word in t[:10]:print(word, freq, sep='\t')
# 简化版本, 注意: 需要去掉开头与结尾的..
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def read_file(file_name):hist = dict()file_data = open(file_name, encoding='utf8')# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率hist: dicthist[lower_word] = hist.get(lower_word, 0) + 1return histdef skip_header(file_obj):for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):breakhist = read_file('emma.txt')# 简化
hist_list = list(hist.items())
hist_list.sort(key=lambda x: x[1], reverse=True)print('The most common word are:')for freq, word in hist_list[:10]:print(word, freq, sep='\t')
13.5 可选形参
我们已经见过一些接收可选形参的内置函数和方法. 用户也可以编写可选参数的自定义函数.
例如, 下面的函数打印一个直方图中最常见的单词:
def print_most_common(hist, num=10):t = most_common(hist)print(The most common word are:)for freq, word in t[:num]:print(word, freq, sep='\t')
第一个形参是必须的, 第二个是可选的. 形参num的默认值是10.
如果值提供一个实参:
print_mosr_common(hist)
num会获得默认值. 如果提供了两个实参:
print_most_common(hist, 20)
num怎会获得提供的实参值. 换句话说, 可选实参值覆盖默认形参值.
如果一个函数即有必须形参, 也有可选形参, 则所有的必须参数都必须在前面, 后面跟着可选形参.
# 完整代码
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def read_file(file_name):hist = dict()file_data = open(file_name, encoding='utf8')# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率hist: dicthist[lower_word] = hist.get(lower_word, 0) + 1return histdef skip_header(file_obj):for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):breakdef most_common(hist):t = []for key, value in hist.items():t.append((value, key))t.sort(reverse=True)return tdef print_most_common(hist, num=10):t = most_common(hist)print('The most common word are:')for freq, word in t[:num]:print(word, freq, sep='\t')hist = read_file('emma.txt')
print_most_common(hist)
# print_most_common(hist, 20)
13.6 字典减法
寻找在书中出现却不再words.txt单词表中的单词, 这个问题可以看作是集合减法;
也就是说, 我们想要找到出现在一个集合(书中的单词)而不在另一个集合(单词表中的单词)的所有单词.subtract函数接收两个字典的d1和d2, 并返回一个新的字典, 包好所有出现在d1中且不出现在d2中的键值.
由于我们并不真的关心字典的值, 我们所有值都设置为None.
def subtract(d1, d2):res = dict()for key in d1:if key not in d2:res[key] = Nonereturn res
要找出书中出现而不在words.txt单词表中的此, 我们可以使用process_file为words.txt建立一个直方图,
再使用减法:
words = process_file('words')
diff = subtract(hist, words)
print("Words in the book that aren't in the word list:")
for word in diff:print(word, end=' ')
下面是<<艾玛>>一书中的部分结果: (结果是一样的, 排序可能不一样, 看你当前版本的字典是否有序!)
# 作者的结果
Words in the book that aren't in the word list:
rencontre jane's blanche woodhouses disingenuseness friend's venice apartment ...
这些词中有些是名字或所有格单词. 其他的如'rencontre'已经不再常用.
但也有一些是真应该包含再单词表中的!
# 我的结果
Words in the book that aren't in the word list:
emma austen i woodhouse a sister's remembrance taylor mr woodhouse's taylor's ...
# 完整代码, 有一点不同, 就是调用函数生成直方图时, 要不要跳过开头的配置...
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def process_file(file_name, is_skip=True):hist = dict()file_data = open(file_name, encoding='utf8')if is_skip:# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率hist: dicthist[lower_word] = hist.get(lower_word, 0) + 1return histdef skip_header(file_obj):for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):break# 字典减法
def subtract(d1, d2):res = dict()for key in d1:if key not in d2:res[key] = Nonereturn res# 跳过靠头结尾
hist = process_file('emma.txt')
# 不跳过开头
words = process_file('words.txt', False)diff = subtract(hist, words)
print("Words in the book that aren't in the word list:")
for word in diff:print(word, end=' ')
1. 练习6
Python提供看一个数据结构set, 它提供了很多常见的集合操作.
你可以读19.5节中的关于集合操作的内容, 或者阅读
http://docs.python.org/3/library/stdtypes.html#type-set
上的文档, 并编写一个程序使用集合减法来寻找出现在书中但不出现再单词表中大单词.
解答: http://thinkpython2.com/code/analyze_book2.py
# 完整代码, 有一点不同, 就是调用函数生成直方图时, 要不要跳过开头的配置...
import string# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def process_file(file_name, is_skip=True):hist = dict()file_data = open(file_name, encoding='utf8')if is_skip:# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率hist: dicthist[lower_word] = hist.get(lower_word, 0) + 1return histdef skip_header(file_obj):for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):break# 集合减法, 集合是无序的, 输出的顺序不一致的...
def subtract(d1, d2):# 小集合 - 大集合return set(d1) - set(d2)# 跳过靠头结尾
hist = process_file('emma.txt')
# 不跳过开头
words = process_file('words.txt', False)diff = subtract(hist, words)
print("Words in the book that aren't in the word list:")
for word in diff:print(word, end=' ')
13.7 随机单词
若要从直方图中随机选择一个单词, 最简单的算法是根据计算得到的频率构造一个列表, 
其中每个单词根据词频有多个拷贝, 并从中随机选择一个单词:
def random(h):t = []for word, freq in h.items():t.append([word] * freq)return random.choice(t)
表达式[word] * freq创建一个列表, 里面有单词word的freq个副本.
entend方法和append类似, 区别是接收的参数是一个序列.这个算法可以使用, 但频率并不高, 每当选择一个随机单词时, 它会重建列表, 而这个列表和原书差不多长.
一个明显的改进方法是至建立列表移除, 再使用多次选择, 但这么做列表任然很大.更好的代替方案如下.
* 1. 使用keys来获的书中所有的单词的列表.
* 2. 构建一个列表, 包含单词频率的累计和(参见练习10-2), 这个列表中的最后一项是书中的总数n.
* 3. 1到n之间随机选择一个数, 使用二分查找(参见练习10-11)来找到随机数再累积和列表中应该出现的位置下标.
* 4. 使用这个下标, 在单词表中找到相应的单词.
1. 练习7
编写一个程序, 使用这个算法来从书中选择一个随机的单词.
解答: analyze_book3.py
import string
import random# 移除符号, 文本中有中文符号“与”
remove_symbol = string.punctuation + string.whitespace + '“”'# 读取文件
def process_file(file_name, is_skip=True):hist = dict()file_data = open(file_name, encoding='utf8')if is_skip:# 跳过开头部分skip_header(file_data)# 现在的file_data以及没有了开头部分.for line in file_data:# 跳过结尾部分if line.startswith('*** END OF THIS PROJECT'):break# 单词很多使用'-'拼在一起, 将'-'替换为空格words_line = line.replace('-', ' ')# 字符串按空格切分words_list = words_line.split()for word in words_list:# 处理单词前后的符号, 中间的不要管word = word.strip(remove_symbol)# 转为全小写lower_word = word.lower()# 统计频率hist: dicthist[lower_word] = hist.get(lower_word, 0) + 1return histdef skip_header(file_obj):for line in file_obj:if line.startswith('*** START OF THIS PROJECT'):break# 创建值的累加列表
def make_count_list(d):count_list = list()count = 0for val in d.values():count = count + valcount_list.append(count)return count_list# 完整单词列表
def full_list(hist):# 单词从1开始full = [' ', ]for k, v in hist.items():for i in range(v):full.append(k)return full# 二分法查找随机值
def dichotomy(tem_list, find, high_index, lower_index=0, index=None, direction=None):# 基准情形len_list = len(tem_list)if len_list == 0:print('找不到', direction)# 当找不到时, 还需要往右切, 则需要加1, 往左则直接返回.# 需要向右切则说明是下一个单词, 向左还在这个单词的范围内, 不需要操作.if direction == 'right':return index + 1if direction == 'left':return index# 获取中间值middle = len_list // 2index = (lower_index + high_index) // 2print(f'当前列表的第{middle}个元素, 原本列表的第{(lower_index + high_index) // 2}个元素.')# 右切 -->if find > tem_list[middle]:lower = middle + 1# lower_index 向右移动middle+1位lower_index = lower_index + lowerindex = dichotomy(tem_list[lower:], find, high_index, lower_index, index, direction='right')return indexelif find < tem_list[middle]:high = middle# 高位向左移动high_index -= (len_list - len(tem_list[:high]))index = dichotomy(tem_list[:high], find, high_index, lower_index, index, direction='left')return indexelse:print('找到了')return index# 随机函数
def randint_num():# 跳过靠头结尾res_hist = process_file('emma.txt')# 创建单词列表g_words_list = list(res_hist.keys())# 每个单词只有一个, 每个值的下标范围很广, 如第一个单词, produced': 15, 那么1-15的坐标都是producedres_count_list = make_count_list(res_hist)# 获取随机数, 从1开始, 如果从0开始第一个单词就多了一次.fin_num = random.randint(1, res_count_list[-1])# 测试数据, 将fin_num替换成列表中的数字# [15[范围在1-15], 588[16-588], 1052, 1053, 1054, 1841, 2124]# 'produced', 'by', 'an', 'anonymous', 'volunteer', 'emma', 'jane',# 查找这个值的下标在哪里# fin_num = 588index = dichotomy(res_count_list, fin_num, len(res_count_list))print(f'精简列表的第{index}位', g_words_list[index])# 使用完整列表测试full = full_list(res_hist)print(f'完整列表中的第{fin_num}位', full[fin_num])randint_num()
"""
精简列表的第58位      mistress
完整列表中的第45709位 been"""
# 作者的代码, 有一点不同的是, 他的随机数和存储单词的位置从0开始, 我从1开始.
import string
import random
from bisect import bisectdef process_file(filename, skip_header):hist = {}fp = open(filename, encoding='utf8')if skip_header:skip_gutenberg_header(fp)for line in fp:if line.startswith('*** END OF THIS'):breakprocess_line(line, hist)return histdef skip_gutenberg_header(fp):for line in fp:if line.startswith('*** START OF THIS'):breakdef process_line(line, hist):line = line.replace('-', ' ')strip_ables = string.punctuation + string.whitespacefor word in line.split():word = word.strip(strip_ables)word = word.lower()hist[word] = hist.get(word, 0) + 1def random_word(hist):# 单词列表words = []# 频率freqs = []# 频率总数total_freq = 0# 遍历键值对for word, freq in hist.items():# 频率总数total_freq += freq# 收录单词words.append(word)# 频率列表freqs.append(total_freq)# 查找的数x = random.randint(0, total_freq - 1)# 返回索引index = bisect(freqs, x)return words[index]hist = process_file('158-0.txt', skip_header=True)print(random_word(hist), end=' ')
13.8 马尔可夫分析
如果你从书中随机地获取单词, 可以凭此感受一下书中地词汇, 但可能无法通过随机获取来得到一句话:
this the small regard harriet which knightley's it most things
一个随机单词地序列, 很难组成有意义地话, 因为相邻地词之间没有任何关联.
例如, 在一个真实地句子中, 冠词'the'应当会后接一个形容词, 而不应是动词或副词.
测量这种类型的关联的方法之一是使用马尔可夫分析, 
它能够用于描述给定地单词序列中下一个可能出现地单词地概率.
例如, 歌曲<<Eric, the Half a Bee>>的开头是:
Half a bee, philosophically,
Must, ipso facto, half not be.
But half the bee has got to be
Vis a vis, its entity. D'you see?
But can a bee be said to be
Or not to be an entire bee
When half the bee is not a bee
Due to some ancient injury?
在这段文本中, 短语'half the'总是后接着单词'bee', 但短语'the bee', 则可能后接'has''is'.
马尔可夫分析的结果是一个从每个前缀('half the' 'the bee')
到其所有可能后缀('has''is')的映射. 给定这种映射后, 你就可以用它来生成随机文件. 
从任意前缀开始, 并从它的可能后缀中随机选择一个.
接着, 你可以将前缀的结尾和后缀组合起来, 作为下一个前缀, 并继续重复.
例如, 如果你以前缀'Half a'开始, 则接下来一个单词必定是'bee', 因为这个前缀在文本中只出现了一次.
下一个前缀, 'a bee', 所以下一个后缀可能是'philosophically', 'be'或者'due'.
在这个例子中前缀的长度总是2, 但其实你可以使用任意前缀长度来进行马尔可夫分析.
1. 练习8
马尔可夫分析:
1. 编写一个程序从文件中读入文本, 并进行马尔可夫分析.结果因该是一个字典, 将前缀映射到可能后缀的集合. 集合可以是列表, 元组或者字典.由你来做出合适的选择, 你可以使用前缀长度2来测试程序, 但编写程序时应当考虑可以方便地改为其他前缀长度.2. 在前面编写地程序中添加一个函数, 基于马尔可夫分析地结果随机生成文本.下面时一个从<<爱玛>>中使用前缀长度2生成地例子:He was very clever, be it sweetness or be angry, ashamed or only amused,at such a stroke. She had never thought of Hannah till you were never meant for me?""I cannot make speechess, Emma:" he soon cut it all himself.对这个例子, 我留下每个单词后面地标点. 结果几乎时语法正确地, 但也不完整正确.语义上, 它看起来像是有意义的, 但也不完全是.当增加前缀长度是, 结果会怎么样? 随机生成的文本会不会看起来更有意义?3. 一旦你的程序可以正常运行后, 可以考虑尝试一下混搭: 如果对两本或更多本书进行组合, 则生成的随机文本会以一种有趣的方式混合各书中的词汇和短语.致谢: 本案例分析基于Kernighan和Pike和The Practice of Programming(Addison-Wesley, 1999)
一书中的一个实例.你应当在继续阅读全尝试这个练习, 接着可从↓下载我的解答:
https://raw.githubusercontent.com/AllenDowney/ThinkPython2/master/code/markov.py
你也需要↓:
https://raw.githubusercontent.com/AllenDowney/ThinkPython2/master/code/emma.txt
'将前缀映射'到可能'后缀的集合', 前缀的两个单词作为键, 后缀最为值, 是一个集合.
相同的值直接添加进去就得了. 
正文第一段 Produced by An Anonymous Volunteer 会转为:{('Produced', 'by'): ['An'],('by', 'An'): ['Anonymous'], ('An', 'Anonymous'): ['Volunteer'],
}第一次运行时, 随机获取一个键(前缀1, 前缀2), 在从它的值中随机选取一个值(rondom_val).
然后修改键为(前缀1修改为前缀2, 前缀2使用值rondom_val), 通过这个键获取对应的后缀的集合, 随机选值.其中有很多单词如:away--you, 不用分开看成一个单词即可.
# 导入模块
import random# 读取文件, 返回单词列表
def make_words_dict(file, prefix_length):# 返回的字典words_dict = dict()# 存储前缀的元组prefix_tuple = tuple()# 文件对象fin = open(file, encoding='utf8')# 遍历文件对象for line in fin:# 去除\n, 对字符串进行切分for word in line.rstrip().split():# 将字符串保存到元组中, 先将元组填充两个元素if len(prefix_tuple) < prefix_length:prefix_tuple += word,continue# 前缀作为键, 后缀作为值words_dict.setdefault(prefix_tuple, []).append(word)# 修改前缀prefix_tuple = prefix_tuple[1:] + (word,)return words_dictdef random_word(word_dict, num=100):# 先随机获取一个键, 通过这个键获取值start_word = random.choice(list(word_dict.keys()))# 前缀元组prefix_tuple = start_wordfor i in range(num):word = random.choice(list(word_dict.get(prefix_tuple)))# 打印值print(word, end=' ')# 修改键, 也是是前缀元组prefix_tuple = prefix_tuple[1:] + (word,)def main():# a.txt 删除了前后说明的正文res_dict = make_words_dict('a.txt', 3)random_word(res_dict)main()
13.9 数据结构
使用马尔可夫分析生成随机文本很有趣, 但这个练习还有一个要点: 数据结构的选择.
在前面的练习中, 你需要选择:
* 如何表达前缀;
* 如何表达可能的后缀的集合.
* 如何表达每个前缀到可能后缀的集合的映射.
最后一个选择很简单, 要从键映射到对应的值, 字典是最自然的选择.
对前缀来说, 最明显的选择是字符串, 字符串列表或者字符串元组.
对后缀来说, 一个选择是列表, 另一种是直方图(字典).
你会如何选择? 第一步需要思考每种数据结构需要实现的操作,
对前缀而言, 我们需要能够从前方删除一个单词, 并在后面添加一个单词.例如, 如果但钱的前缀是'Half a', 而下一个单词是'bee', 则需要能够构造下一个前缀. 'a bee'.
你的第一个选择可能是列表, 因为列表添加和删除元素都很方便.
但我们也需要使用前缀作为字典的键, 所以列表被排除掉, (字典的键必须是不可变类型).
对元组而言, 虽然你不能附加或删除, 但可以使用加法操作符来构造一个新的元组:
def shift(prefic, word):# 前缀元组的后一个元素 + word 组成新的元组.return prefic[1:] + (word, )
shift接收一个单词的元组, prefix, 以及一个字符串word, 
并构建一个新的元组, 包含prefi中除了一个元素之外的元素, 并把word添加在最后.对后缀集合而言, 我们需要进行的操作包括添加一个新的后缀(或者增加一个已有的后缀的频率, '直方图'), 
以及随机选择一个后缀.添加一个新后缀, 使用列表实现或者直方图实现效率上相同.
从一个列表中随机选择元素很简单; 从直方图中随机选择则更难一些(参见练习13-7).
到处为止我们一致在讨论实现的简易性, 但选择数据结构时, 还有其他需要考虑的因素.
* 1. 一个时运行时间.有时候, 我们可以从理论上预期一种数据结构比另一种更快.例如, 我们提到过in操作符, 当元素数量很大时, 在字典中使用比在列表中快.但哪种实现会更快常常无法事先预知. 一个办法时两种都实现, 在比较那个更快.这种方法称为基准比较(benchmarking). 比较实际的方案是先选择最容易实现的数据结构, 然后看它是否对预期的程序而言足够快.如果已经足够, 则不需要变动.否则, 可以使用profile模块之类的工具, 发现程序中哪些地方占用了最长的时间.* 2. 另外一个考虑因素是存储空间.例如, 使用直方图来保存后缀集合可能占用较少空间,因为不论一个单词在文本中出现多少次, 你只需要保存一次.有的情况下, 节省空间也可以让你的程序运行更快, 而在极端的情形中, 如果导致内存溢出, 则程序无法正常运行. 但对大多数程序来说, 存储空间是次于运行速度的第二考虑因素.
最后一点: 在这个讨论中, 对于分析和生成两个过程, 我暗示了我们应当使用相同的数据结构.
但因为这是两个分开的阶段, 所以也可以在分析阶段使用一种数据结构, 
再转换为另一种数据结构用于生成阶段.
如果新的数据结构在生成阶段节省的时间大于转换花费的时间, 则总的来说是有利的.意思是: 
分析阶段使用一种数据结构,.
生成阶段时转为另一种数据结构(类型可能需要进行转换, 转换需要消耗时间).
如果使用新的数据类型节省的时间大于转换花费的时间, 则是有利的(其实还要考虑存储空间的问题).
13.10 调试
但在调试程序时, 尤其是对付一个困难的bug时, 尝试下面5:
* 1. 阅读审读你的代码, 对自己读出来, 并检查它是否和你想说的一致.* 2. 运行做一些小修改并进行试验, 或者运行不同的版本.通常如果在程序中正确的地方加上正确的输出, 问题就会变得更加显而易见.但有时候你需要构建一个脚手架.* 3. 沉思花些时间思考! 可能是哪种类型的错误: 语法错误, 运行时的还是语义的?从错误消息或程序输出中可以得到什么信息?哪种错误可能导致你看到的问题? 在问题出现之前, 你的最后一次修改是什么?* 4. 橡皮鸭调试如果你向别人解释遇到的问题, 有时候在说完问题之前就能找到答案.通常你甚至不需要找人去述说, 而只是需要对橡皮鸭诉说即可.这是著名的橡皮鸭调试(rubber, duck debugging)的来源.这可不是我编出来的, 参见: https://enwikipedia.org/wifi/Rubber_duck_debugging.* 5. 回退在某种情况下, 最好的方法就是回退, 撤销最近的修改, 直到你的程序恢复到之前没有错误且能够理解的程度. 然后可以开始重新构建.新手程序员会有时开在这个环节中的某一个上, 却忘了还可以尝试其他的环节.每个环节都有其独自的失败模式.例如, 当问题时一个拼写错误时, 阅读代码可以帮忙, 但若问题时概念误解导致, 就没有效果了.如果你不理解自己的程序, 俺么即使阅读100, 也发现不了问题, 因为错误是在你大脑中.运行一些实验代码可以起到很大的帮助, 尤其是哪些短小而简单的测试程序.但如果你没有思考或阅读代码就运行试验代码, 则可能会陷入我称为'随机走动编程'的模式之中.即毫无目标地随机改变程序, 直到程序正确运行为止, 还无疑问, 随机走动编程可能要花费很长地时间.但如果有太多地错误, 或者你要修正地代码太大, 太复杂, 即使用最好地调试技巧也会失败.有时候最好地选择是回退, 简化程序, 直达得到一个你能够理解并且正常运行的程序.新手程序员往往不愿意后撤, 他们无法忍受删除一行代码(即使那是错误的代码).如果能让你感觉更好, 可以将程序复制到另一个文件再开始删减它.这样以后就可以一点一点的复制回来.寻找一个困难的bug, 需要阅读, 运行, 沉思, 甚至有时候需要回退.如果你在这其中一个环节上卡住了, 可以尝试其他的环节.
13.11 术语表
确定性(deterministic): 程序的一种特性: 给定相同的输入, 每次运行都会执行相同的操作.伪随机(pseudorandom): 一序列数: 看起来是随机的, 但实际上是由带着确定性的程序生成的.默认值(default value): 可选参数声明时给定的值, 如果函数调用时没有指定这个实参, 则使用该默认值.覆盖(override): 使用实参值替换一个默认值.基准测试(benchmarking): 实现不同的备选方案, 并使用各种可能输出的样本来测试它们, 以达到选择使用哪种数据结构的目的.橡皮鸭调试(rubber duck debugging): 通过向类似橡皮鸭之类的静物解释你的问题, 进行调试的过程.虽然橡皮鸭不懂Python, 但通过诉说和解释, 可以帮助你解决问题.
13.12 练习
1. 练习9
一个单词的'排名', 时它在单词列表中按频率排序的位置: 最常见的单词排名第1, 次常用的词排第2, 等等.
齐普夫定律(Zipf's law)描述了排名和自然语言中词频的关系(http://en.wikipedia.org/wiki/Zipfs_law).
特别地, 它预测了排名为r地单词地频率f: f = cr-s
这里的s和c是依赖于语言和文件本的参数. 如果在表达时两侧都调用对数, 则得到:
log f = log c - slog r
所以如果以log r为横轴给log绘图, 则会得到斜率为-s, 截距为logc的直线.
编写一个程序, 从文本中读入文本, 计算单词词频, 以及log f和log r.
使用你喜欢的制图程序将结果以图标形式展示出来, 并检查它是否为直线, 你能估计s的值吗? 
解答: https://raw.githubusercontent.com/AllenDowney/ThinkPython2/master/code/zipf.py
要运行我的解答, 你需要安装绘图模块matplotlib.
如果安装过Anaconda, 你就已经有了matplotlib, 否则你可能需要安装它.
如果出现: ImportError: DLL load failed while importing _cext: 找不到指定的模块.
则是numpy模块出错了, numpy是在安装matplotlib时安装的.
默认安装的时1.24.2版本, 退回到旧版本1.22.4.* 1. 终端输入下面指令卸载卸载numpy和matplotlib的命令:pip uninstall numpypip uninstall matplotlib* 2. 在http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy 下载numpy下载与本机安装的python版本一致numpy, 注意其中符号含义, 一定要选择带mkl的numpy.前面的1.22.4为numpy的版本号, 一般选择最新版本即可.中间的cp39表示对应python3.9.x版本..后面的win_amd64表示对应的电脑的64* 3. 安装本地软件包命令:pip install 安装包路径* 4. 最后安装matplotlib即可pip install matplotlib
import string
import matplotlib.pyplot as pltdef process_file(filename, skip_header):hist = {}fp = open(filename, encoding='utf8')if skip_header:skip_gutenberg_header(fp)for line in fp:if line.startswith('*** END OF THIS'):breakprocess_line(line, hist)return histdef skip_gutenberg_header(fp):for line in fp:if line.startswith('*** START OF THIS'):breakdef process_line(line, hist):line = line.replace('-', ' ')strippables = string.punctuation + string.whitespacefor word in line.split():word = word.strip(strippables)word = word.lower()hist[word] = hist.get(word, 0) + 1def rank_freq(hist):# 获取值的列表freqs = list(hist.values())# 排序, 降序freqs.sort(reverse=True)# 列表生成式, 元组列表, 使用枚举函数, 获取(index, 与值), 索引从0开始, 设置为从1开始.rf = [(r + 1, f) for r, f in enumerate(freqs)]return rfdef plot_ranks(hist, scale='log'):# 得到一个元组列表 [(1, 5223), (2, 5183), (3, 4822), (4, 4279)...]t = rank_freq(hist)# 将所有元组最为zip的参数, 将index存放在一个元组中, 频率存在一个元组中.rs, fs = zip(*t)plt.clf()plt.xscale(scale)plt.yscale(scale)plt.title('Zipf plot')plt.xlabel('rank')plt.ylabel('frequency')# 划线, 线宽为3plt.plot(rs, fs, 'r-', linewidth=3)plt.show()def main(filename='emma.txt'):hist = process_file(filename, skip_header=True)plot_ranks(hist)main()

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

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

相关文章

Leetcode498. 对角线遍历

Every day a Leetcode 题目来源&#xff1a;498. 对角线遍历 解法1&#xff1a;模拟 根据题目要求&#xff0c;矩阵按照对角线进行遍历。设矩阵的行数为 m&#xff0c;矩阵的列数为 n&#xff0c;我们仔细观察对角线遍历的规律可以得到如下信息&#xff1a; 一共有 mn−1 条…

JUC并发编程-第一天

JUC并发编程-第一天 JUC开发基础知识进程、线程、协程 JUC开发基础知识 先有进程&#xff0c;然后进程可以创建线程&#xff0c;线程是依附在进程里面的&#xff0c;线程里面包含多个协程 进程之间不共享全局变量&#xff0c;线程之间共享全局变量(线程通信就是用的这个&#x…

EasyExcel文件导出,出现有文件但没有数据的问题

一开始由于JDK版本过高&#xff0c;我用的17&#xff0c;一直excel没有数据&#xff0c;表头也没有&#xff0c;后来摸索了好久&#xff0c;找了资料也没有&#xff0c;后来改了代码后报了一个错误&#xff08;com.alibaba.excel.exception.ExcelGenerateException: java.lang.…

使用pnpm创建vue3项目

https://pnpm.io/zh/ 全局安装&#xff1a; npm install -g pnpm 检查版本&#xff1a; pnpm -v 创建vue3项目&#xff1a; pnpm create vuelatest 项目装包&#xff1a; pnpm install 运行项目&#xff1a; pnpm dev 命令行&#xff1a; https://pnpm.io/zh/pnpm-cli pnpm …

NFT 智能合约实战-快速开始(1)NFT发展历史 | NFT合约标准(ERC-721、ERC-1155和ERC-998)介绍

文章目录 NFT 智能合约实战-快速开始(1)NFT发展历史国内NFT市场国内NFT合规性如何获得NFT?如何查询NFT信息?在 OpenSea 上查看我们的 NFT什么是ERC721NFT合约标准ERC-721、ERC-1155和ERC-998 对比ERC721IERC721.sol 接口内容关于合约需要接收 ERC721 资产 onERC721Received…

vue3+vite:动态引入静态图片资源

目录 第一章 前言 第二章 vue2与vue3动态引入静态图片资源 2.1 vue2 webpack动态引入静态图片资源 2.1.1 了解 2.1.2 vue2项目动态引入静态图片资源 2.2 vue3 vite动态引入静态图片资源 2.2.1 了解 2.2.2 require vs import了解 2.2.3 vue3vite 项目动态引入静态图片…

CRC计算单元

CRC计算单元 CRC是Cyclic Redundancy Check,循环冗余校验的缩写. 是一种检测数据错误的技术,主要用在数据通信和数据存储的方面. 但是这种技术只能检测到传输或存储的数据是否有误,没有将错误纠正的功能. 而CRC计算单元是一个独立的具备CRC计算功能的外设. AT32 MCU片上CRC计…

禁渔期水域监管:EasyCVR视频智能监控方案

一、背景与需求分析 根据农业部印发的《中国渔政亮剑2024系列专项执法行动方案》&#xff0c;我国将持续推进长江十年禁渔、海洋伏季休渔、黄河等内陆重点水域禁渔等专项行动。根据四川省相关规定&#xff0c;每年3月1日至6月30日为禁渔期&#xff0c;在此期间&#xff0c;四川…

构建汛期智慧水利新生态:EasyCVR视频汇聚监控综合管理方案解析

一、项目背景与目标 随着我国水利事业的不断发展&#xff0c;水利设施的管理与维护工作愈发重要。随着夏季汛期的到来&#xff0c;水利管理工作面临着巨大的挑战。为确保水利设施的安全运行&#xff0c;及时应对可能出现的汛情&#xff0c;建设一套高效、智能的视频监控可视化…

后继者00

题目链接 后继者 题目描述 注意点 题目中的树是二叉搜索树节点p在二叉搜索树中一定存在 解答思路 本题关键是找到值大于节点p的值的第一个节点&#xff0c;因为本题中的树是二叉搜索树&#xff0c;所以左子树的值始终小于根节点&#xff0c;右子树的值始终大于根节点访问到…

31、shell循环

一、循环 循环&#xff1a;循环是一种重复执行一段代码的结构。只要满足循环的条件&#xff0c;会一直执行这个代码。 循环条件&#xff1a;在一定范围之内&#xff0c;按照指定的次数来执行循环。 循环体&#xff1a;在指定的次数内&#xff0c;执行的命令序列。只要条件满…

力扣42 接雨水

听说字节每人都会接雨水&#xff0c;我也要会哈哈哈 数据结构&#xff1a;数组 算法&#xff1a;核心是计算这一列接到多少雨水&#xff0c;它取决于它左边的最大值和右边的最大值&#xff0c;如下图第三根柱子能接到的雨水应该是第一根柱子高度和第五根柱子高度的最小值减去第…

DDei在线设计器-属性编辑器

DDei-Core-属性编辑器 DDei-Core-属性编辑器插件包含了文本、大文本、数值、下拉、单选、勾选以及颜色等属性编辑。 图形和属性共同构成一个完整的定义&#xff0c;属性编辑器就是编辑属性值的控件。当选中图形实例时&#xff0c;属性面板就会展现当前实例的所有属性以及属性编…

qt仿制qq登录界面

#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {// 设置窗口大小this->resize(window_width, window_heigth);// 固定窗口大小this->setFixedSize(window_width, window_heigth);// 设置窗口图标this->se…

怎么学习汇川Codesys PLC教程?

前言 各位好&#xff0c;我在B站和抖音上都有发布视频的&#xff0c;搜索我的名称“阿凡工控分享”即可。在CSDN上发表文章也是想把我的一点见解和经验分享出来&#xff0c;进一步的方便大家进行学习。 我是正文 本文主要也是为了方便大家学习汇川的Codesys PLC而制作的&…

登录/注册- 滑动拼图验证码(IOS/Swift)

本章介绍如何使用ios开发出滑动拼图验证码&#xff0c;分别OC代码和swift代码调用 1.导入项目model文件OC代码&#xff08;下载完整Demo&#xff09; 2.放入你需要显示的图片 一&#xff1a;OC调用 #import "ViewController.h" #import "CodeView.h"…

讯飞有一个可以根据描述文本自动生成PPT的AI接口,有趣

文档&#xff1a;https://www.xfyun.cn/doc/spark/PPTGeneration.html 价格方面提供了免费1000点的额度&#xff0c;生成一次是10点&#xff0c;正好100次&#xff0c;如果要购买的话最低要购买1344元的&#xff0c;没有按量付费的模式&#xff0c;个人小开发者可买不起。 让我…

【简单介绍下Sass,什么是Sass?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

波拉西亚战记加速器 台服波拉西亚战记免费加速器

波拉西亚战记是一款新上线的MMORPG游戏&#xff0c;游戏内我们有多个角色职业可以选择&#xff0c;可以体验不同的战斗流派玩法&#xff0c;开放式的地图设计&#xff0c;玩家可以自由的进行探索冒险&#xff0c;寻找各种物资。各种随机事件可以触发&#xff0c;让玩家的冒险过…

LabVIEW缝缺陷图像标注库

LabVIEW缝缺陷图像标注库 开发了一个基于LabVIEW平台构建的船舶焊缝缺陷图像标注库。该库旨在通过高效和简洁的方式处理和标注船舶焊缝缺陷图像&#xff0c;提高缺陷识别的准确性和效率&#xff0c;进而保障船舶的结构安全。 项目背景 在船舶制造过程中&#xff0c;焊接质量…