python自學日記6——列表

學習python時記錄本身或觀察別人從錯誤到正確的思路遠比只看正確答案效果好——傅查理python

1.編寫一個函數,接收一個數字列表,並返回其累積和,例如[1,2,3]的累積和爲[1,3,6]

看到求和想到前面用到的內置函數sum(t),可是sum只說了是求列表內全部值的和,不知道能不能求部分和,因此須要作一下測試app

t=[1,2,3]
sum(t[:2])

返回值是3,表示能夠用sum,而後得出以下代碼:dom

def cumulative_sum(t):
    res=[]
    for i in range(len(t)-1): #剛開始想着後面有i+1,之前這裏都是須要減一的,可是忽略了":(i+1)"是不包括右側的i+1的,因此不用減一
        res.append(sum(t[:(i+1)]))
    return res
t=[1,2,3]
cumulative_sum(t)

返回值是[1,3],因此把減一去掉就能夠了函數

def cumulative_sum(t):
    res=[]
    for i in range(len(t)):
        res.append(sum(t[:(i+1)]))
    return res
t=[1,2,3]
cumulative_sum(t)

這裏有兩點須要注意下,res後用append,我剛開始寫成了res[i]=sum(t[:(i+1)]),這把字典和列表方法弄混,另外就是忘記了t[:(i+1)]中的「:」,也形成報錯,須要注意下這些細節地方,這些bug是能夠直接顯示出來的,可是剛纔那個減一是顯示正常可是不符合預期結果,由於咱們知道預期結果,因此才能檢查出問題,若是不知道那就難了,寫代碼時仍是須要提早想清楚。學習

列表刪除元素有三種方法,需注意三者區別和是否有返回值:測試

  1. t.pop(),pop修改列表,並返回被刪除掉的值,默認刪除最後一個
  2. del t[i],刪除後不返回值,可使用切片刪除多個值
  3. 若是你知道要刪除的元素而不知道下標,可使用remove,返回值是None

對象和值:rest

a='banana'
b='banana'
a is b

輸出是Truecode

c=[1,2,3]
d=[1,2,3]
c is d

輸出是False對象

前面a和b咱們會說他們是相同的,在這個例子裏python只創建了一個自發貨車對象,而a和b都引用了它。排序

然後面兩個咱們能夠說c和d是相等的,由於他們有相同的元素,但他們不是相同的。由於他們並非同一個對象。若是兩個對象相同,則否則相等,若是相等,但不必定相同。注意區分相同和相等。

區分修改列表的操做和新建列表的操做十分重要。例如append是修改列表,「+」則是新建列表。

t1=[1,2]
t2=t1.append(3)
print(t1)
print(t2)
[1, 2, 3]
None #t2返回None說明t1.append(3)沒有返回值
t3=t1+[4]
print(t3)
[1, 2, 3, 4]

切片操做會新建一個列表

def tail(t):
    return t[1:]
letters=['a','b','c']
rest=tail(letters)
print(rest)
['b', 'c']

2.編寫一個函數is_anagram,接收兩個字符串,當他們互爲迴文時返回True

給的提示是兩個單詞,若是從新排列其中一個的字母能夠獲得另外一個則互爲迴文,這個提示我是看懂了,可是感受不太對,上網查了下也只查了些詩中有互爲迴文的,可是那個寫的是前面說的互爲倒序的,那麼就奇怪了,互爲迴文和互爲倒序有什麼區別,暫時先按照提示來寫吧

def is_anagram(word1,word2):
    if word1.sorted()==word2:
        return True
    return False
is_anagram('ab','ba')
AttributeError                            Traceback (most recent call last)
<ipython-input-72-85d6d5401dcc> in <module>
      4         return True
      5     return False
----> 6 is_anagram('ab','ba')

<ipython-input-72-85d6d5401dcc> in is_anagram(word1, word2)
      1 #練習:編寫一個函數is_anagram,接收兩個字符串,當它們互爲迴文時返回True
      2 def is_anagram(word1,word2):
----> 3     if word1.sorted()==word2:
      4         return True
      5     return False

AttributeError: 'str' object has no attribute 'sorted'

報錯提示字符串不能使用sorted,多是記錯了,那用下sort試一下

def is_anagram(word1,word2):
    if word1.sort()==word2:
        return True
    return False
is_anagram('ab','ba')

結果仍是報一樣的錯誤,而後纔想起字符串是不能更改的,若是想排序看樣子得先把字符串變成列表才行

def is_anagram(word1,word2):
    if "".join(list(word1).sort())==word2 or "".join(list(word2).sort())==word1:
        return True
    return False
is_anagram('hello','ab')

個人想法是先把字符串變成列表,而後排序,後面在用「」.join把分開的字母從新拼在一塊兒,結果報錯以下:

<ipython-input-74-716276a7e28b> in is_anagram(word1, word2)
      1 def is_anagram(word1,word2):
----> 2     if "".join(list(word1).sort())==word2 or "".join(list(word2).sort())==word1:
      3         return True
      4     return False
      5 is_anagram('hello','ab')

TypeError: can only join an iterable

有個懷疑是sort()沒返回值,而後嘗試了下確實沒有,那用sorted(t)試了下有返回值,而後把代碼改爲下面這樣:

def is_anagram(word1,word2):
    if "".join(sorted(list(word1)))==word2 or "".join(sorted(list(word2)))==word1:
        return True
    return False
is_anagram('hello','ello')

此次就正常了,仍是如前面講的,注意有沒有返回值很重要。

3.生日悖論

編寫一個函數has_duplicates接收一個列表,當其中任何一個元素出現多於一次時,返回True.它不該當修改原始列表

首先想到的就是對列表中每一個元素數一下個數,當任何一個超過1時返回True

def has_duplicates(t):
    for s in t:
        if t.count(s)>1:
            return True 
    return False
t=[1,3,2]
has_duplicates(t)

固然若是是本身以前不知道count(我也是上網查了用法),能夠用笨辦法,首先排序,而後挨個判斷相鄰元素是否相同

def has_duplicates1(t):
    new_t=t[:] #生成新的列表
    new_t.sort() #由於這個會修改列表,不會生成新的列表
    for i in range(len(new_t)-1):
        if new_t[i]==new_t[i+1]:
            return True
    return False
t=[1,3,3]
has_duplicates1(t)

若是大家班有23個學生,那麼其中有兩人生日相同的概率有多大?可使用random模塊中的randint生成隨機整數

去查了下官方文檔,知道了randint的用法,一次只能生成一個隨機數,那麼想生成23個就須要用到循環,下面還須要計算機率須要調用,因此生成一個函數

def random_birt(students):
    t=[]
    for i in range(students):
        t.append(random.randint(1,366))
    return t
# random_birt(23)
        
def count_match(students,numbers):
    t=random_birt(students) #應該放到循環裏,不然只生成一個隨機列表,結果都是同樣的
    count=0
    for i in range(numbers):
        if has_duplicates(t):
            count+=1
    return count
count_match(23,1000)

返回值時1000,一想就不對,發現隨機列表沒有放到循環裏,放到循環裏後以下

def random_birt(students):
    t=[]
    for i in range(students):
        t.append(random.randint(1,366)) #一年按365天算,因此生成隨機數範圍是1到365
    return t
# random_birt(23)
        
def count_match(students,numbers):
    
    count=0
    for i in range(numbers):
        t=random_birt(students)
        if has_duplicates(t):
            count+=1
    return count
count_match(23,1000)

返回值494,說明1000次中有494次出現兩我的生日相同。機率接近50%

4.編寫一個函數bisect,接收一個排好序的列表,以及一個目標值,當目標值在列表之中,返回其下標,不然None

想直接用find方法,試了下發現list是不能用find的,而後經過循環一個個比對了

def bisect(t,target):
    for i in range(len(t)):
        if t[i]==target:
            return i
    return None
t=[1,2,3,4,5,6]
bisect(t,5)

上述方法是將列表中全部的元素拿出來與目標一一比對,可是這有個問題就是若是列表很長就會形成速度比較慢,所以咱們能夠用二分查找(須要列表是有序的),bisect模塊(可見官方文檔)用於二分查找:

import bisect
def find_lt(a,x):
    i=bisect.bisect_left(a,x) #bisect.bisect_left(a, x, lo=0, hi=len(a)),在a中找到x合適的插入點,使得x左側都小於x,右側大於等於x    
    if i != len(a) and a[i]==x:
        return i
    return None
t=read_words()
find_lt(t,'hello')

二分查找大大下降了查找速度,若是單詞列表有113809個,按照第一種方法就要查找相應次數,按照第二種大概17步就能夠找到。

5.讀取文件words.txt生成一個列表

import time
def read_words():
    fin=open('words.txt')
    t=[]
    for line in fin:
        word=line.strip()
        t.append(word)
    return t
start_time=time.time()
t=read_words()
elapsed_time=time.time()-start_time
print(len(t))
print(t[:10])
print(elapsed_time)

6.編寫一個程序找到單詞表中互爲倒序的單詞對

互爲倒序的意思是「ad"和」da「這樣就是,因此剛開始想着從頭開始循環,檢查每一個單詞的倒序單詞是否在單詞表中便可,而後代碼以下:

def remove_dumplicates(t): #爲了去重,不過在驗證主程序是否可行前還沒調用函數
    new_t=[]
    for i in range(len(t)):
        if t[i] not in new_t:
            new_t.append(t[i])
    return new_t
# t=[1,[1,2],[2,1]]
# remove_dumplicates(t)
def daoxu():
    a=[]
    t=read_words()
    for s in t:
        if s[::-1] in t:
            a.append(sorted([s,s[::-1]]))
    return a
daoxu()

一直用挨個查找的方法用習慣了,上來隨手就寫成這樣,運行的時候發現忽略了運行時間了。十萬個單詞,每一個單詞反向而後再查找一遍,具體時間就算不過來了,挺長的,因此須要用到二分查找,改爲以下

import bisect
def remove_dumplicates(t): #去重列表中重複的元素
    new_t=[]
    for i in range(len(t)):
        if t[i] not in new_t:
            new_t.append(t[i])
    return new_t

def find_lt(a,x): #二分查找
    i=bisect.bisect_left(a,x)
    if i != len(a) and a[i]==x:
        return True
    return None
def daoxu():
    a=[]
    t=read_words() #用到上面生成字母表的列表
    for s in t:
        if find_lt(t,s[::-1])==True and s!=s[::-1]:
            a.append(sorted([s,s[::-1]]))
    return remove_dumplicates(a)
daoxu()

得出的反向對須要兩兩不能相同,因此s!=s[::-1],而後再去重,最後就得出所要的結果了。

7.編寫一個程序找到單詞表中全部互鎖的單詞

互鎖:兩個單詞,從每一個單詞中交錯去除一個字母能夠組成一個新的單詞,咱們稱之爲互鎖,例如shoe和code能夠互鎖爲schooled

個人思路是將單詞表中的每一個單詞根據下標的奇偶分別拆分紅兩個單詞,而後查找這兩個單詞是否都在單詞表中,若是在就是互鎖,不在就不是,可是在將一個單詞拆分時遇到了問題:

for i in range(len('hello')):
    s1=[]
    s2=[]
    if i%2!=0:
        s1.append(['hello'[i]])
    elif i%2==0:
        s2.append('hello'[i])
print(s1,s2)

返回不符合預期,後面發現是s1和s2放到循環中了,應該放在外面。

s1=[]
s2=[]
for i in range(len('hello')):
    
    if i%2!=0:
        s1.append('hello'[i])
    elif i%2==0:
        s2.append('hello'[i])
print(s1,s2)

這樣就分紅了兩個列表了,而後經過join將列表拼接成單詞

def husuo():
#     a=[]
    t=read_words() #獲取單詞表
    for s in t:
        s1=[]
        s2=[]
        for i in range(len(s)):
            
            if i%2!=0: #奇數下標
                s1.append(s[i]) #將全部奇數下標組成一個列表
            elif i%2==0: #偶數下標
                s2.append(s[i]) #將全部偶數下標組成一個列表
        word1=''.join(s1)  #將列表拼接成字符串
        word2=''.join(s2)
        if find_lt(t,word1) and find_lt(t,word2): #查找兩個單詞同時在單詞表中的狀況
            print(word1+'   '+word2 +'     '+s)
#     return a
husuo()

這個問題我想的是兩兩組成詞再查找運算量太大,並且麻煩,反向思考將單詞拆分,而後查找就好一些。另外就是大問題要學會拆解成小問題,如前面兩步就是看能不能本身把一個單詞拆分紅奇偶列表。

三互鎖單詞按照上面的邏輯稍微改一下就好了:

def husuo():
#     a=[]
    t=read_words()
    for s in t:
        s1=[]
        s2=[]
        s3=[]
        for i in range(len(s)):
            
            if i%3==0:
                s1.append(s[i])
            elif i%3==1:
                s2.append(s[i])
            else:
                s3.append(s[i])
        word1=''.join(s1)
        word2=''.join(s2)
        word3=''.join(s3)
        if find_lt(t,word1) and find_lt(t,word2) and find_lt(t,word3):
            print(word1+'   '+word2 +'     '+word3+'      '+s)
#     return a
husuo()

下面是答案代碼:

from inlist import *


def interlock(word_list, word):
    """Checks whether a word can be split into two interlocked words.

    word_list: list of strings
    word: string
    """
    evens = word[::2]
    odds = word[1::2]
    return in_bisect(word_list, evens) and in_bisect(word_list, odds) 
        

def interlock_general(word_list, word, n=3):
    """Checks whether a word can be split into n interlocked words.

    word_list: list of strings
    word: string
    n: number of interleaved words
    """
    for i in range(n):
        inter = word[i::n]
        if not in_bisect(word_list, inter):
            return False
    return True
        

if __name__ == '__main__':
    word_list = make_word_list()
    
    for word in word_list:
        if interlock(word_list, word):
            print(word, word[::2], word[1::2])


#    for word in word_list:
#        if interlock_general(word_list, word, 3):
#            print (word, word[0::3], word[1::3], word[2::3])

我發如今將一個一個單詞拆分這塊本身作得複雜了,用切片更簡單一些,下次得注意下。

相關文章
相關標籤/搜索