《Think Python 2e》作业实现(十): 列表

《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
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于一个自学程序设计的入门者而言,他需要一本什么样的书呢?我认为标准有以下三个: 第一,介绍足够用的知识。这一点看似简单,但是却不易掌握,像许多人推荐的 A Byte of Python,内容就明显过少了,而处于另一个极端的 Learning Python 篇幅超过一千页,又明显超出入门者的需要。对于程序设计初学者而言,他们所需要的是(a)编程语言的基本特性;(b)程序设计的基本原则和思想。在这一点上 Think Python 就做得不错,240页的篇幅虽然不大,但是由于文风简洁紧凑,已经涵盖了程序设计的基本方面,甚至连 Debugging 这样的话题都有比较深入的探讨。 第二,具有足够而具有挑战性的习题。学习编程语言和学习外语有类似之处,要真正掌握必须经历在学习区刻意练习的过程,所谓学习区,就是你需要付出一定努力才能达到的区域。但是许多书籍题目设计并不完善,往往题目数量不够且挑战性不足,达不到刻意练习的要求。Think Python 的课后习题的编排我认为是非常出色的,首先题目本身非常有趣,其中不少题目取自 Car Talk 的 Puzzler 节目;其次题目的练习强度也基本足够,Allen B. Downey 在官方网站上提供的部分习题答案范例总行数达到了 8456 行(统计包含注释和空行),如果连同在 Python Shell 练习的代码,读完全书所写过的代码不会少于 2500 行;最后,题目本身具有一定的挑战性,绝对不是书中范例的简单重复,其中不少习题是给出提示要求你改进书中的范例。总而言之,在这方面我对 Think Python 也是比较满意的。 第三,内容有趣。现在许多流行的编程入门书(例如 Head First 系列)表面上看很有趣,但是细读下来很快就会对书中那些简单而又虚假的问题感到厌烦。Think Python 中所涉及的问题在深度上要更胜一筹,具有一定的难度,能让人静下心来真正思考问题的解决方案,而且书中的不少章节所解决的问题也具有实用性,例如 Case study: data structure selection 这一章中就涉及文本词频的分析、生成随机文本等问题,Files 这一章则涉及了根据 MD5 寻找重复文件的问题等等。 说完这本书的优点,再简单说说这本书的缺点,主要还是一些细节问题:例如,string 的不少 method 没有涵盖到;pickle 不介绍 dump 和 load,而是介绍了 dumps 和 loads;List Comprehension 只是一笔带过,没有细讲;异常方面的介绍实在太过精简,如此重要的话题应当多花些笔墨介绍;在 OOP 的部分太过拖沓,前面两章大可合并精简,而且 __init__ method 完全可以更早引入,以利于培养良好的编程风格。不过总体来说瑕不掩瑜。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值