2020-04
22

写得过于简单了吧

By xrspook @ 9:29:12 归类于: 烂日记

我看的那个中文版Think Python 2的第11章,习题几乎可以这么说,没一道题的相关是做对的。有些东西,习题跟现在的Think Python 2英文版不一样,我觉得可能是英文版修正了某些东西。修正完以后,英文版并没有写什么更新说明之类的东西,但即便有,中文版翻译的人翻译完以后大概也不会时刻关注英文版有没有变动。同一道题的关联引用,这种东西怎么可以凭着感觉来呢?第一次遇到的时候,我云里雾里,因为按照中文版的那个说法,在某一章书的习题里根本找不到那个东西,但在我印象中,我的确是做过那些习题,到底是在哪一章书里的呢?另外一个版本的中文版那里的索引做对了。当我回看英文原版的时候,发现他们引用某个习题真的写得超简单,但是那些习题全部都是有超连接的,而且锚点到了某一章书的某个确切位置。所以我看的那个中文版之所以是现在这个样子,是不是因为他只是进行了文字上的翻译,还没有仔细研究那些超链接之类的东西呢?又或者在他翻译的时候,他并不是看着英文电子版,我是看英文纸质或者PDF等没有超链接之类的东西。电子版这种东西最让人觉得舒服的应该是哪怕你不标明是那是哪一章书的习题,你只是说那是习题几,只要你把超链接做上去,一切好办。

我看的那个中文版让我无语,但是英文原版也好不到哪里去。因为英文原版的作者脑洞实在太大,让人不知道如何言表。我觉得变成编程这东西,你得给出一个范围,然后再给出一个参考结果,才能让人有奔头。但是他只叫你这般测试,然后再给出一个参考的脚本。在不看脚本之前,如果我只是运行的脚本,而一开始的时候,我们设定的自定义参数不同,该如何判断读者自己的脚本写得对不对呢?有些参数他们完全可以先给出来,或者你会说,那岂不是成了一个提示。这又不是测验考试,重要的不是结果,而是如何整出那个结果,所以即便给你看到最终结果,你不懂过程,还是折腾不出来。英文原版的作者把那些条件参数写在他的脚本里面,而当你写自己的脚本的时候,你又清楚明白到你必须得设定那些参数,但是应该确定为什么呢?拿不准。这就会进入一个怪圈。首先是读者看着题目,自己解答,解答完以后测试,觉得没问题,打开参考答案运行,因为参数答案的结果跟读者得到的不一样,接着我们还得去仔细研究参考答案到底用了什么参数。然后把那个参数放在我们自己的脚本里再运行。对比两个运行的效果。这不是非常折腾吗?如果没有那个隐藏的参数,读者完全可以自己运行一遍,拿参考答案再运行一遍,对比结果就行了。我们最终要做到的不就是那个结果吗?当然,如果得出结果完全一致以后,还是建议大家再研究一下参考答案跟自己的脚本有什么区别,想一想这些区别会不会导致什么问题。

Think Python 2这本书,不只是习题参数设置很让人迷茫。在某些章节里,写得也不细致,比如说元组那一章。元组这个东西据说在其他编程语言里面是没有的。在介绍元组之前,已经说过字符串、列表以及字典。前面三个东西一个套一个,挺容易理解,但是加了元祖进去以后,世界就变得混沌了。因为列表字典元组这三个东西可以互相组合互相转化。有些可变,有些不可变。有些人可排序,有些无效。要真的说清楚元组,第12章书里面已经说到的东西以及已经举过的例子还不足以解决问题。如果他们不把所有东西都说一遍,起码他们得给我们一个列表。告诉我们这些东西可以控制元组,至于具体的使用方法,大家可以查手册。

或许当我把一整本书都看完以后,我的想法又不是我现在这个了。

2020-04
21

找2个词汇表

By xrspook @ 17:59:37 归类于: 扮IT

最根本的在于做好词语的切片和组合,知道要找什么词,丢到字典里找那是秒杀的事。我不知道他们为什么这么折腾,直接在有音标的词汇表里找不就得了,但偏偏要两个词汇表都要求同时存在,于是循环判断神马不得不多一层。幸好字典里用in那是非常简单快捷的事。

Exercise 6: Here’s another Puzzler from Car Talk (http://www.cartalk.com/content/puzzlers): This was sent in by a fellow named Dan O’Leary. He came upon a common one-syllable, five-letter word recently that has the following unique property. When you remove the first letter, the remaining letters form a homophone of the original word, that is a word that sounds exactly the same. Replace the first letter, that is, put it back and remove the second letter and the result is yet another homophone of the original word. And the question is, what’s the word? Now I’m going to give you an example that doesn’t work. Let’s look at the five-letter word, ‘wrack.’ W-R-A-C-K, you know like to ‘wrack with pain.’ If I remove the first letter, I am left with a four-letter word, ’R-A-C-K.’ As in, ‘Holy cow, did you see the rack on that buck! It must have been a nine-pointer!’ It’s a perfect homophone. If you put the ‘w’ back, and remove the ‘r,’ instead, you’re left with the word, ‘wack,’ which is a real word, it’s just not a homophone of the other two words. But there is, however, at least one word that Dan and we know of, which will yield two homophones if you remove either of the first two letters to make two, new four-letter words. The question is, what’s the word? You can use the dictionary from Exercise 1 to check whether a string is in the word list. To check whether two words are homophones, you can use the CMU Pronouncing Dictionary. You can download it from http://www.speech.cs.cmu.edu/cgi-bin/cmudict or from http://thinkpython2.com/code/c06d and you can also download http://thinkpython2.com/code/pronounce.py, which provides a function named read_dictionary that reads the pronouncing dictionary and returns a Python dictionary that maps from each word to a string that describes its primary pronunciation. Write a program that lists all the words that solve the Puzzler. Solution: http://thinkpython2.com/code/homophone.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pronounce import read_dictionary
from time import time
def set_dict(fin):
    d ={}
    for line in fin:
        word = line.strip()
        d[word] = 0
    return d
def same_pronounce(a, b, c, mydict, pdict):
    if b in mydict and c in mydict:
        if b in pdict and c in pdict:
            if pdict[a] == pdict[b] and pdict[a] == pdict[c]:
                return True
    return False
start = time()
count = 0
pdict = read_dictionary()
fin = open('words.txt')
mydict = set_dict(fin)
for word in mydict:
    if word in pdict:
        word1 = word[1:]
        word2 = word[:1] + word[2:]
        if same_pronounce(word, word1, word2, mydict, pdict):
            print(word, word1, word2)
            count += 1
print(count)
end = time()
print(end - start)
# llama lama lama
# llamas lamas lamas
# scent cent sent
# 3
# 0.28800010681152344
2020-04
21

字典真牛

By xrspook @ 12:03:27 归类于: 扮IT

字典用好了以后666得不知道该如何形容。创造字典,搜索词典,快得就像眨眼间。列表需要考虑的长度问题,字典里一个in就高效快捷了。

这是一道扯淡的习题,因为条件没固定,参考答案可以怎么参考呢?

Exercise 5: Two words are “rotate pairs” if you can rotate one of them and get the other (see rotate_word in Exercise 5). Write a program that reads a wordlist and finds all the rotate pairs. Solution: http://thinkpython2.com/code/rotate_pairs.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def rotate_word(something, n): # a-z: 97-122, A-Z: 65-90
    newletter1 = ''
    for letter in something:
        if ord(letter) < ord('A') or ord('Z') < ord(letter) < ord('a') or ord('z') < ord(letter):
            newletter2 = newletter1 + letter
        else:
            if ord(letter) + n > ord('z'):
                newletter2 = newletter1 + chr(ord(letter) + n - 26)
            elif ord('a') > ord(letter) + n > ord('Z'):
                newletter2 = newletter1 + chr(ord(letter) + n - 26)
            else:
                newletter2 = newletter1 + chr(ord(letter) + n)
        newletter1 = newletter2
    return newletter2
def set_dict(fin):
    d = {}
    for line in fin:
        word = line.strip().lower()
        d[word] = 0
    return d
fin = open('words.txt')
count = 0
d = set_dict(fin)
for word in d:    
    for i in range(1, 14): # 8.13.5的习题没有说要移多少位,参考答案直接定义为1-14位,你猜我在想什么
        if rotate_word(word, i) in d:
            print(word, i, rotate_word(word, i))
            count += 1
print(count)
# ......
# zax 1 aby
# zax 4 deb
# zebu 7 glib
# zebu 10 jole
# zee 1 aff
# zee 9 inn
# zips 12 lube
# zoa 6 fug
# zoa 12 lam
# 1137
2020-04
21

循序渐进

By xrspook @ 9:25:39 归类于: 烂日记

我觉得必定把我搞死的筛选词汇表里的二锁三锁单词,居然不怎么费劲就做出来了。

第一次,我在里面用了一个很傻的循环,其实根本就没有必要。可以不用自己的循环就千万不要在词汇表搜索时多用,但我的第一次尝试并不是毫无意义的,,因为已经能得出结果了,而且结果是对的,虽然非常慢,慢到我无法忍受程序继续运行下去。然后,我把要搜索的东西全部都丢到二分法搜索里面,循环只剩下一个必须做的,因为要把词汇表过一遍。第一次做二词互锁的时候,我在一个循环里套了两个if,然后我又把那两个if做成平行的,其实也就是把两个本来嵌套起来的条件用一个and连接起来,很多时候我们都需要这么干。因为除了要二锁,还要考虑三锁,显然人肉去做这些判断,写一大堆一模一样的东西实在太无聊,所以我又自定义了一个新函数,把需要判断的东西全部都丢掉里面,最终返回True或者False。其实,之前我已经考虑过要直接这么干,但因为前天在做搜索回文词的时候我已经得出了回文词的索引,所以直接用就好。我个人觉得,效果是差不多的。

在搜索互锁单词的时候,输出时我用的是字符串的变体。因为二分法搜索被我丢到了一个多条件复合的判断函数里面,所以返回的东西,只有True与False。如果全部都是True的话,就意味着那些单词辩题应该全部都OK没问题。也正是因为输出的东西已经没有索引返回,所以结果我直接使用单词的变体表示。这样的效果很惊人。之前我套用了两个if,然后我写了一个判断函数把条件都含进去了,这样的改进让脚本的运行时间缩短了一半。如果一开始我没有见过两秒多的那个效果,我肯定不会为一秒多的那个惊叹。这是我一步一步琢磨出来了的。

首先是实现得出结果,然后是对语句进行重构,接下要让这个程序适用于二、三词互锁,所以我做的东西是泛化。一开始我把所有判断都写在主程序里,后来我又把它分出一个函数,也就是封装。无意之中,我在执行着Think Python第四章里说到的开发方法:写小程序、封装、泛化、重构。无论是大程序还是小程序,其实都会经历这些。我会从一些我最熟悉的东西开始实现功能。但是我最熟悉的东西不意味着效率一定会高。循环再循环以后,得出一个词都要好几秒时间,实在让人难以接受,尤其当这个词到下个时中间要相隔几秒甚至是十几秒才有反应的时候。这就逼迫着我一定要改进,不同的语句能实现同样的功能,但是它们之间的效率是非常不一样。

大家都在用着二分法的思路去搜索,但是我的脚本就比参考答案快接近30倍。单词一蹦出来,我就知道我一定会比参考答案快。因为我的程序里,单词是噼里啪啦完全没有停顿就全部出来的,而参考答案的词语出来的时候虽然不会一直有,但总有一些顿卡现象,那相对于我的程序来说,就像是慢镜头。

我从来没有想过自己能做得比参考答案还要好,或许他们要做到的并不是有多快。相比于不是二分法的搜索,二分法已经很快了。他们想做到的,大概是用最简练的语言,用模块化的方法实现功能,效率倒不是他们最看重的,因为做搜索词汇表这种事在列表里完成肯定比不上直接上字典。但是,如果不曾在列表里面死去活来,又怎么会体验到字典的神奇。

无论我的二分法搜索写得多么高效,肯定还是不如字典的。我体验过用词典进行斐波那契常数计算。当要计算第40个的时候,一般的递归和字典递归简直就是天渊之别。

如果不曾经历,不曾被整得很惨,我大概就不能说自己真学会了那个东西。

2020-04
20

更爽

By xrspook @ 12:00:26 归类于: 扮IT

战胜参考答案从昨晚开始貌似就成了我最大的快乐。互锁词的生成要比昨天的回文词复杂一些,因为这意味着搜索的次数更多了。虽然都是用二分法搜索的思路,但我就是要比参考答案快接近30倍肿么破。至于为什么会这样,我没有研究,或许我应该仔细研究一下。

10万条的单词表里:二词互锁1254条,我用时1.4秒,参考答案用时39.1秒;三词互锁991条,我用时1.5秒,参考答案用时43.4秒。一箩筐的成就感啊啊啊啊啊啊啊~~~

Exercise 12: Two words “interlock” if taking alternating letters from each forms a new word. For example, “shoe” and “cold” interlock to form “schooled”. Solution: http://thinkpython2.com/code/interlock.py. Credit: This exercise is inspired by an example at http://puzzlers.org. Write a program that finds all pairs of words that interlock. Hint: don’t enumerate all pairs! Can you find any words that are three-way interlocked; that is, every third letter forms a word, starting from the first, second or third?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import time
def in_bisect(library, first, last, myword): # 二分法搜索,10万数据查询最多只需不到20步
    if first > last: # 这是一句拯救了我的条件
        return -1
    else:
        mid = (first + last)//2
        if myword == library[mid]:
            return mid
        elif library[mid] > myword:
            return in_bisect(library, first, mid-1, myword)
        else:
            return in_bisect(library, mid+1, last, myword)
def interlock(library, i, num):
    m = 0
    n = num
    while m < num:
        if in_bisect(library, 0, len(library)-1, library[i][m::n]) == -1:
            return False
        else:
            m += 1
            n -+ 1
    return True
count = 0
library = []
fin = open('words.txt')
for line in fin:
    word = line.strip()
    library.append(word)
library.sort()
start = time.time()
# for i in range(len(library)-1): # 二词互锁
#     if interlock(library, i, 2):
#         print(library[i], library[i][::2], library[i][1::2])
#         count += 1
for i in range(len(library)-1): # 三词互锁
    if interlock(library, i, 3):
        print(library[i], library[i][::3], library[i][1::3], library[i][2::3])
        count += 1
print(count)
end = time.time()
print(end - start)
# 1254, 1.3558001518249512 # 二词互锁 xrspook解法
# 1254, 39.10080027580261  # 二词互锁 参考答案
# 991, 1.4504001140594482  # 三词互锁 xrspook解法
# 991, 43.366000175476074  # 三次互锁 参考答案
© 2004 - 2026 我的天 | Theme by xrspook | Power by WordPress