《Think Python 2e》作业实现(十): 列表
文章目录
这是什么?
这里是《Think Python 2e》作业实现 !在这里将记录《Think Python 2e》作业的练习记录、终端信息和结果分析。
- 这是《Think Python 2e》哪个版本的作业?
《Think Python:如何像计算机科学家一样思考》第二版。这里主要参考了一个中文网页版《Think Python 2e》中译本。- 可以当成《Think Python 2e》参考答案吗?
这里主要记录了我自己完成作业时所产生的成果及习题总结,基本未参考教材所提供的答案,未免有失规范,参考答案建议还是以 绿茶出版社官方代码 为准。- 不同的解释器版本结果不尽相同,这里用的哪个版本Python解释器?
这里用了Python 3.8.6版解释器,部分用安卓Pydroid 4.01_arm64中的3.8.3版Python解释器,在线解释器用教程推荐的PythonAnywhere中的3.8版Python解释器。
习题10-1:累加嵌套列表元素
【习题 】 编写一个叫做 nested_sum 的函数,接受一个由一些整数列表构成的列表作为参数,并将所有嵌套列表中的元素相加
- 练习记录:
def nested_sum(t):
t1 = []
for it in t:
it1 = sum(it)
t1.append(it1)
return t1
a = [[1, 2, 3], [4, 5], [6], [7, 8]]
print(nested_sum(a))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\nested_sum.py
[6, 9, 6, 15]
习题10-2:元素累加和的新列表
【习题 】 编写一个叫做 cumsum 的函数,接受一个由数值组成的列表,并返回累加和,即一个新列表,其中第 i 个元素是原列表中前 i+1 个元素的和
- 练习记录:
def cumsum(t):
t1 = []
it1 = 0
for it in t:
it1 += it
t1.append(it1)
return t1
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(cumsum(a))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\cumsum.py
[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
习题10-3:去头去尾后的新列表
【习题 】 编写一个叫做 middle 的函数,接受一个列表作为参数,并返回一个除了第一个和最后一个元素的列表
- 练习记录:
def middle(t):
t1 = t[1:-1]
return t1
a = [1, 'b', 3, 4, [5, 6]]
print(middle(a))
print(a)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\middle.py
['b', 3, 4]
[1, 'b', 3, 4, [5, 6]]
习题10-4:列表去头去尾
【习题 】 编写一个叫做 chop 的函数,接受一个列表作为参数,移除第一个和最后一个元素,并返回None
- 练习记录:
def chop(t):
t.pop(0)
t.pop(-1)
a = [1, 'b', 3, 4, [5, 6]]
print(chop(a))
print(a)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\chop.py
None
['b', 3, 4]
习题10-5:元素是否递增排列
【习题 】 编写一个叫做 is_sorted 的函数,接受一个列表作为参数,如果列表是递增排列的则返回 True ,否则返回 False
- 练习记录:
def is_sorted(t):
t1 = t[:] # 备份一个列表 t
t1.sort()
if t == t1 :
return True
return False
x = [1, 2, 3]
y = ['a', 'c', 'b']
print(is_sorted(x), is_sorted(y))
print(x, y)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\is_sorted.py
True False
[1, 2, 3] ['a', 'c', 'b']
- 结果分析:
t1 = t[:]
语句是为列表 t 建立了一个备份列表 t1,t1 = t
语句只是为列表 t 取了个别 t1,用列表方法 sort 为 t1 重新排序意味着 t 也重新排序,这里只能用备份语句- 列表方法 sort 没有返回值,所以类似
t1 = t.sort()
的语句并不能为 t1 赋值
习题10-6:两个单词是不是变位词
【习题 】 如果可以通过重排一个单词中字母的顺序,得到另外一个单词,那么称这两个单词是变位词,编写一个叫做 is_anagram 的函数,接受两个字符串作为参数,如果它们是变位词则返回 True
- 练习记录:
def is_anagram(word1, word2):
a1 = []
for letter1 in word1:
a1.append(letter1)
a1.sort()
a2 = []
for letter2 in word2:
a2.append(letter2)
a2.sort()
if a1 == a2:
return True
return False
print(is_anagram('face', 'cafe'))
print(is_anagram('oh', 'ooh'))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\is_anagram.py
True
False
习题10-7:列表中有重复的元素吗
【习题 】 编写一个叫做 has_duplicates 的函数,接受一个列表作为参数,如果一个元素在列表中出现了不止一次,则返回 True ,这个函数不能改变原列表
- 练习记录:
def has_duplicates(t):
t1 = t[:]
t1.sort()
for i in range(len(t1)-1):
if t1[i] == t1[i + 1]:
return True
return False
a = [1, 2, 3, 4]
b = [1, 2, 3, 1]
c = [1,[4,5,6],2,3,[4,5,6]]
print(has_duplicates(a))
print(has_duplicates(b))
print(has_duplicates(c))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\has_duplicates.py
False
True
Traceback (most recent call last):
File "D:\WorkSpace\thinkpython2e\has_duplicates.py", line 14, in <module>
print(has_duplicates(c))
File "D:\WorkSpace\thinkpython2e\has_duplicates.py", line 3, in has_duplicates
t1.sort()
TypeError: '<' not supported between instances of 'list' and 'int'
- 结果分析:列表方法 sort 只支持列表元素同为数值或者同为字符串时的重新排序,所以本程序中的函数 has_duplicates 只能判别元素同为数值或者同为字符串时是否有重复元素
- 变形练习:使得函数适应任何种类元素的列表
def has_duplicates(t):
t1 = t[:]
for i in range(len(t1)-1):
for j in range(i + 1, len(t1)):
if t1[i] == t1[j]:
return True
return False
a = [1, 2, 3, 4]
b = [1.1, 2, 3, 1.1]
c = [1,'a',2,3,'a']
print(has_duplicates(a))
print(has_duplicates(b))
print(has_duplicates(c))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\has_duplicates_1.py
False
True
True
习题10-8:班上两个同学同生日概率
【习题 】 如果你的班级上有23个学生, 2个学生生日相同的概率是多少? 你可以通过随机产生23个生日,并检查匹配来估算概率,提示:你可以使用 random 模块中的 randint 函 数来生成随机生日
- 练习记录:
import random
def list_birthdays():
b = []
for i in range(23):
birthday = int(random.randint(1, 366))
b.append(birthday)
return b
def has_duplicates(t):
t1 = t[:]
t1.sort()
for i in range(len(t1)-1):
if t1[i] == t1[i + 1]:
return True
return False
def probability_has_duplicates(n):
m = 0
for i in range(n):
if has_duplicates(list_birthdays()):
m += 1
p = m/n*100
return p
print('probability_has_duplicates:', probability_has_duplicates(1000000), '%')
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\probability.py
probability_has_duplicates: 50.6167 %
- 结果分析:
- 本题程序假设一个班上同学都是同一学年出生的即都是上一年9月2日到下一年9月1日期间出生的
- 本题假设该学年的二月份有29天(全学年共366天),假设该学年只有365天,则概率提高
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\probability.py probability_has_duplicates: 50.7383 %
习题10-9:两种不同算法哪个慢
【习题 】 编写一个函数,读取文件 words.txt ,建立一个列表,其中每个单词为一个元素,编写两个版本,一个使用 append 方法,另一个使用 t = t + [x] ,哪个版本运行得慢?为什么?
import time
def time_append():
time_start = time.time()
fin = open('words.txt')
t = []
for str in fin:
t.append(str)
time_end = time.time()
time_cost = time_end - time_start
return time_cost
def time_plus():
time_start = time.time()
fin = open('words.txt')
t = []
for str in fin:
t += [str]
time_end = time.time()
time_cost = time_end - time_start
return time_cost
def time_lists_append(n):
time_costs = 0
for i in range(n):
time_costs += time_append()
return time_costs
def time_lists_plus(n):
time_costs = 0
for i in range(n):
time_costs += time_plus()
return time_costs
print('time_lists_append:', time_lists_append(1000))
print('time_lists_plus:', time_lists_plus(1000))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\time_1.py
time_lists_append: 37.00023698806763
time_lists_plus: 40.03238892555237
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\time_1.py
time_lists_append: 46.19033455848694
time_lists_plus: 41.723203897476196
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\time_1.py
time_lists_append: 41.634233236312866
time_lists_plus: 43.88629508018494
- 结果分析:通过各运行两种算法1000次进行比较,重复比较三次,各有快慢,理论上两种算法应该一样快,因为都是进行了113809次在列表末尾添加一个元素的运算
习题10-10:字符串在列表中的位置
【习题 】 编写一个叫做 in_bisect 的函数,接受一个已排序的列表和一个目标值作为参数,返回该值在列表中的位置,如果不存在则返回 None
- 练习记录:
def in_bisect(t, str):
t1 = t
lenth = len(t)
while lenth > 0:
lenth = int(len(t1)/2)
if str < t1[lenth]:
t1 = t1[:lenth]
elif str > t1[lenth]:
t1 = t1[lenth:]
elif str == t1[lenth]:
return t.index(str)
return
t = []
fin = open('words.txt')
for line in fin:
line1 = line.strip()
t.append(line1)
print(in_bisect(t, 'aa'))
print(in_bisect(t, 'hello'))
print(in_bisect(t, 'zymurgy'))
print(in_bisect(t, 'hellooo'))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\in_bisect.py
0
45100
113808
None
习题10-11:搜索反转词对三种算法
【习题 】 两个单词中如果一个是另一个的反转,则二者被称为是“反转词对”,编写一个函数,找出单词表中所有的反转词对
- 练习记录:
import time
def in_bisect(t, str):
lenth = int(len(t)/2)
if lenth < 1:
if str == t[-1]:
return True
return False
if str < t[lenth]:
return in_bisect(t[:lenth], str)
if str > t[lenth]:
return in_bisect(t[lenth:], str)
if str == t[lenth]:
return True
def inversion_words():
time_start = time.time()
t = []
t_inversion_words = []
n = 0
fin = open('words.txt')
for line in fin:
line1 = line.strip()
t.append(line1)
for word in t:
if in_bisect(t, word[::-1]):
if word != word[::-1]:
n += 1
t_inversion_words.append(word)
t_inversion_words.append(word[::-1])
time_end = time.time()
time_cost = time_end - time_start
print(n, time_cost)
return t_inversion_words
inversion_words()
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\is_inversion.py
794 230.37748169898987
- 结果分析:
import time
语句导入计时模块 - 变形练习:(比较三种算法运算速度)
import time
def is_inversion(str1, str2):
if str1 == str2[::-1]:
return True
return False
def inversion_words_1():
time_start = time.time()
fin = open('words.txt')
t = []
for line in fin:
line1 = line.strip()
t.append(line1)
for i in range(len(t)-1):
for j in range(i+1, len(t)):
if is_inversion(t[i], t[j]):
time_end = time.time()
time_cost = time_end - time_start
print(t[i], t[j])
return time_cost
def inversion_words_2():
time_start = time.time()
fin = open('words.txt')
t = []
for line in fin:
line1 = line.strip()
t.append(line1)
for i in range(len(t)-1):
for j in range(i+1, len(t)):
if t[i] == t[j][::-1]:
time_end = time.time()
time_cost = time_end - time_start
print(t[i], t[j])
return time_cost
def in_bisect(t, str):
lenth = int(len(t)/2)
if lenth < 1:
if str == t[-1]:
return True
return False
if str < t[lenth]:
return in_bisect(t[:lenth], str)
if str > t[lenth]:
return in_bisect(t[lenth:], str)
if str == t[lenth]:
return True
def inversion_words_3():
time_start = time.time()
t = []
fin = open('words.txt')
for line in fin:
line1 = line.strip()
t.append(line1)
for word in t:
if in_bisect(t, word[::-1]):
if word != word[::-1]:
time_end = time.time()
time_cost = time_end - time_start
print(word, word[::-1])
return time_cost
print(inversion_words_1())
print(inversion_words_2())
print(inversion_words_3())
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\is_inversion_1.py
abut tuba
19.838346481323242
abut tuba
13.85999608039856
abut tuba
0.8674938678741455
- 结果分析:由于前两种算法计算量太大,为了对比三种算法运算速度,以发现第一个反转词对为对比对象;可以看出,第一、第二种算法唯一差异是第一种部分语句编写了一个函数 is_inversion,可以看出,函数调用耗时略多;而前两种算法与第三种算法,耗时有十几倍的差异;算法很重要,对计算效率有重大影响
习题10-12:搜索单词表中的连锁词
【习题10.12.1 】 编写一个程序,找出单词表中所有的连锁词,提示:不要枚举所有的单词对
- 练习记录:
import time
def pair(word):
word1 = ''
word2 = ''
for i in range(len(word)):
if i % 2 == 0:
word1 += word[i]
if i % 2 == 1:
word2 += word[i]
return word1, word2
def t():
t = []
fin = open('words.txt')
for line in fin:
word = line.strip()
t.append(word)
return t
time_start = time.time()
n = 0
t = t()
for word in t:
word1, word2 = pair(word)
if word1 in t and word2 in t:
n += 1
print(n, ':', word, '>', word1, '+', word2)
time_end = time.time()
time_cost = time_end - time_start
print(time_cost)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\pair_2.py
1 : aahs > ah + as
2 : abbey > aby + be
3 : abied > aid + be
4 : abies > ais + be
5 : abri > ar + bi
...
1252 : year > ya + er
1253 : yeas > ya + es
1254 : yuan > ya + un
244.46866941452026 242.014173746109
- 结果分析:
- 习题要求不枚举所有的单词对,那只能枚举所有的单词能否由词对连锁而成,当然这样的枚举计算量还是要小很多
- 在程序中引用了计时模块
import time
,经对程序以及if word1 in t and word2 in t:
语句运行计时可知,if word1 in t and word2 in t:
语句耗费了绝大多数程序运算时间 (244.46866941452026 秒中的 242.014173746109 秒),可见 in 运算特别耗时
【习题10.12.2 】 你能够找到三重连锁的单词吗?即每个字母依次从3个单词得到
- 练习记录:
import time
def pair(word):
word1 = ''
word2 = ''
word3 = ''
for i in range(len(word)):
if i % 3 == 0:
word1 += word[i]
if i % 3 == 1:
word2 += word[i]
if i % 3 == 2:
word3 += word[i]
return word1, word2, word3
def t():
t = []
fin = open('words.txt')
for line in fin:
word = line.strip()
t.append(word)
return t
time_start = time.time()
time_cost1 = 0
n = 0
t = t()
for word in t:
word1, word2, word3 = pair(word)
time_start1 = time.time()
if word1 in t and word2 in t and word3 in t:
n += 1
print(n, ':', word, '>', word1, '+', word2, '+', word3)
time_end1 = time.time()
time_cost1 += time_end1 - time_start1
time_end = time.time()
time_cost = time_end - time_start
print(time_cost, time_cost1)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\pair_3.py
1 : abacuses > ace + bus + as
2 : abalone > ale + bo + an
3 : abalones > ale + bos + an
4 : abased > as + be + ad
5 : abaser > as + be + ar
...
990 : womera > we + or + ma
991 : wooers > we + or + os
255.65914750099182 253.231294631958