亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

USF MSDS501 計(jì)算數(shù)據(jù)科學(xué)中文講義 2.4 Python 中的編程

系統(tǒng) 1749 0
來(lái)源: ApacheCN『USF MSDS501 計(jì)算數(shù)據(jù)科學(xué)中文講義』翻譯項(xiàng)目

原文:Programming Patterns in Python

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

現(xiàn)在我們已經(jīng)了解了計(jì)算機(jī)如何組織數(shù)據(jù),并進(jìn)行一些低級(jí)編程操作,現(xiàn)在讓我們看一些常見(jiàn)的高級(jí)編程模式。 每一個(gè)這些操作都有一個(gè)使用條件和循環(huán)模式的實(shí)現(xiàn),我們可以使用 python 語(yǔ)法很容易地表達(dá)。我們也可以使用現(xiàn)有的庫(kù)函數(shù)來(lái)實(shí)現(xiàn)相同的功能,我們也將探索它們。

當(dāng)我們進(jìn)行時(shí),你會(huì)發(fā)現(xiàn)程序設(shè)計(jì)和編程是一個(gè)單詞關(guān)聯(lián)的游戲。 高級(jí)操作(例如 map )應(yīng)該在您的腦海中觸發(fā)偽代碼(類似英語(yǔ)的“代碼”)的循環(huán)模板,然后應(yīng)該觸發(fā) for-each Python 代碼模板。

請(qǐng)記住 ,我們通過(guò)選擇和應(yīng)用操作來(lái)設(shè)計(jì)程序,而不是特定的代碼序列。編程是設(shè)計(jì)過(guò)程中的最后一步,我們?cè)谶@里獲得可執(zhí)行文檔。因此,直觀地思考如何操作數(shù)據(jù)列表,或從數(shù)據(jù)中提取信息。我經(jīng)常把事情畫(huà)出來(lái)或者把它們放到電子表格中,來(lái)幫助我想象。在紙上手動(dòng)移動(dòng)一些數(shù)據(jù)有助于我理解要執(zhí)行的操作。

在設(shè)計(jì)了高級(jí)操作的序列或組合之后,我們可以用偽代碼或直接使用 Python 語(yǔ)法來(lái)寫(xiě)出東西。隨著您獲得更多經(jīng)驗(yàn),從操作直接轉(zhuǎn)到代碼將更容易,但我們?nèi)匀辉谑褂貌僮鞫皇谴a來(lái)設(shè)計(jì)程序。對(duì)于復(fù)雜的問(wèn)題,盡管有 35 年以上的編程經(jīng)驗(yàn),我仍然寫(xiě)出偽代碼。

編程模式

選擇程序的整體計(jì)劃時(shí),程序員從一組模式或模板中提取。個(gè)別行動(dòng)本身也是如此。程序員有一個(gè)常見(jiàn)操作目錄,他們?cè)谶x擇計(jì)劃步驟時(shí)依賴他。

毫無(wú)疑問(wèn),您熟悉以下操作:

  • 求和列表中的數(shù)字
  • 計(jì)數(shù)列表中的數(shù)字

但我們可以將這些進(jìn)一步抽象為:

  • 查找滿足條件的列表中的所有值
  • 對(duì)列表中的每個(gè)元素應(yīng)用操作
  • ......

操作越抽象,它就越廣泛適用。我們使用的操作類型部分取決于程序員的風(fēng)格,但很大程度上受編程語(yǔ)言的能力及其預(yù)先存在的功能庫(kù)的影響。

數(shù)據(jù)練習(xí)

在我們?yōu)g覽這些材料時(shí),我們將做幾個(gè)小練習(xí)。 請(qǐng)將此 Python 代碼剪切并粘貼到您正在使用的筆記本中。

請(qǐng)嘗試在不查看練習(xí)描述正下方的解決方案的情況下進(jìn)行練習(xí)。

          
            UnitPrice = [38.94, 208.16, 8.69, 195.99]
Shipping = [35, 68.02, 2.99, 3.99, 5.94, 4.95, 7.72, 6.22]
names=['Xue', 'Mary', 'Bob']
Oscars = [
    [1984, "A Soldier's Story", 0],
    [1984, 'Places in the Heart', 0],
    [1984, 'The Killing Fields', 0],
    [1984, 'A Passage to India', 0],
    [1984, 'Amadeus', 1],
    [1985, "Prizzi's Honor", 0],
    [1985, 'Kiss of the Spider Woman', 0],
    [1985, 'Witness', 0],
    [1985, 'The Color Purple', 0],
    [1985, 'Out of Africa', 1]
]
Quantity = [6, 49, 27, 30, 19, 21, 12, 22, 21]
A = [
    [1, 3, 10],
    [4, -9, 0],
    [2, 5, 8]
]
B = [
    [7, 4, 0],
    [4, 3, 1],
    [1, 6, 8]
]
first=['Xue', 'Mary', 'Robert']
last=['Li', 'Smith', 'Dixon']
          
        

累積

讓我們從一個(gè)非常簡(jiǎn)單但非常常見(jiàn)的模式開(kāi)始,稱為累積。該模式遍歷一系列元素并累積一個(gè)值。例如,為了對(duì)序列中的數(shù)字求和,我們使用帶有 + 運(yùn)算符的累加器運(yùn)算。當(dāng)我們遍歷序列時(shí),我們更新一個(gè)初始化為 0 的流動(dòng)總和:

在 Excel 中,這就像在單元格中使用 sum(...) 。在 Python 中,這種模式的實(shí)現(xiàn)有一個(gè)初始化步驟和一個(gè)循環(huán):

          
            sum = 0
for q in Quantity:
    sum += q # same as: sum = sum + q
print(sum)

# 207
          
        

我們可以使用我們想要的任何其他算術(shù)運(yùn)算符,例如 * 。實(shí)際上,我們可以使用任何帶有兩個(gè)操作數(shù)并返回新值的函數(shù)。 對(duì)于求和,函數(shù)的兩個(gè)“輸入”數(shù)字是先前的累計(jì)值和序列中的下一個(gè)值。該函數(shù)的結(jié)果是新的累計(jì)值。 + * 是最常見(jiàn)的運(yùn)算符。

您還將在 Hadoop 和 Spark 的分布式計(jì)算世界中,看到這個(gè)名為 reduce (歸約)的操作,就像 map/reduce 那樣。

計(jì)數(shù)器 是累加器的一種特殊情況,它計(jì)算序列中元素的數(shù)量。它還使用 + 運(yùn)算符,但兩個(gè)“輸入”數(shù)字是先前的累計(jì)值和固定的值 1,而不是序列中的下一個(gè)元素。

我們可以更新多個(gè)流動(dòng)的累計(jì)值,而不只是一個(gè)。例如,假設(shè)我們想要計(jì)算序列中偶數(shù)和奇數(shù)值的數(shù)量。我們需要兩個(gè)累加器,從零開(kāi)始,但操作是相同的:

+1 表示每一步應(yīng)用的“向累加值加 1”的操作,但僅在當(dāng)前值為偶數(shù)或奇數(shù)時(shí)才應(yīng)用。在 Python 代碼中,我們將執(zhí)行以下操作:

          
            even = 0
odd = 0
for q in Quantity:
    if q % 2 == 0: even += 1 # % is mod operator
    else: odd += 1
print(even, odd)

# 4 5
          
        

映射

也許最常見(jiàn)的操作是,將一個(gè)序列映射到另一個(gè)序列,將運(yùn)算符或函數(shù)應(yīng)用于每個(gè)元素。(它就像一個(gè)累加器,它累積了一個(gè)項(xiàng)目列表,而不是一個(gè)單獨(dú)的值。)例如,使用電子表格創(chuàng)建一個(gè)新列,包含 5% 折扣的單價(jià),在電子表格中如下所示:

我們可以使用列表字面值,在時(shí)間 0 處表示兩個(gè)列表:

          
            UnitPrice = [38.94, 208.16, 8.69, 195.99]
Discounted = [] # empty list
          
        

換句話說(shuō):

從高級(jí)操作到偽代碼到代碼,我們頭腦中的翻譯過(guò)程是 單詞關(guān)聯(lián) 游戲。當(dāng)你的大腦看到將一列數(shù)據(jù)映射到另一個(gè)數(shù)據(jù)的操作時(shí),請(qǐng)考慮“映射”。當(dāng)你的大腦聽(tīng)到“映射”,它應(yīng)該生成適當(dāng)?shù)膫未a循環(huán),適當(dāng)?shù)靥畛淦巍.?dāng)你的大腦聽(tīng)到“對(duì)于每個(gè)等等等等”時(shí),請(qǐng)考慮“哦,for-each 循環(huán)”并使用適當(dāng)?shù)木幊棠J剑?

          
            Discounted = [] # empty list
for price in UnitPrice:
    Discounted.append(price * 0.95)
print(Discounted)

# [36.992999999999995, 197.75199999999998, 8.2555, 186.1905, 20.691, 6.308, 6.935, 40.62199999999999, 131.23299999999998]
          
        

請(qǐng)注意,我已將空列表的初始化包含在此代碼段中。原因是我們真的想在心理上,將初始化與此代碼模式相關(guān)聯(lián)。

即使在微觀層面,也要考慮將操作映射到代碼。例如,當(dāng)我想到“將 x 添加到列表 y ”時(shí),我的大腦會(huì)將其轉(zhuǎn)換為 y.append(x)

用于映射操作的列表推導(dǎo)式

這是一種常見(jiàn)的模式,Python 有一個(gè)顯式結(jié)構(gòu),使事情變得更容易。它被稱為 列表推導(dǎo)式 ,它實(shí)際上只是簡(jiǎn)寫(xiě),看起來(lái)更像數(shù)學(xué)集符號(hào):

          
            Discounted = [price * 0.95 for price in UnitPrice] # a list comprehension
print(Discounted)

# [36.992999999999995, 197.75199999999998, 8.2555, 186.1905, 20.691, 6.308, 6.935, 40.62199999999999, 131.23299999999998]
          
        

練習(xí)

在不查看我們剛才所做的代碼的情況下,嘗試使用列表推導(dǎo)來(lái)為映射操作編寫(xiě)代碼,該列表推導(dǎo)將價(jià)格除以 2,再次將值放在 Discounted 中。 不要剪切/粘貼。輸入它!

          
            Discounted = [price/2 for price in UnitPrice] # a list comprehension
print(Discounted)

# [19.47, 104.08, 4.345, 97.995]
          
        

練習(xí)

給定一個(gè)名稱列表, ['Xue', 'Mary', 'Robert'] ,用代碼實(shí)現(xiàn)一個(gè)映射操作,將名稱轉(zhuǎn)換為 namelens 列表,它包含名稱長(zhǎng)度。提示:函數(shù)調(diào)用 len('Xue') 返回 3。 不要剪切/粘貼。輸入它!

          
            names = ['Xue', 'Mary', 'Robert']
namelens = [len(name) for name in names]
print(namelens)

# [3, 4, 6]
          
        

組合

讓我們看一下代碼模式,一次遍歷兩個(gè)列表,將結(jié)果放在第三個(gè)列表中。例如,要計(jì)算銷售交易的成本,我們將數(shù)量乘以單位價(jià)格。在電子表格中,如下所示:

將該公式拖到“成本”列中,將公式應(yīng)用于以下行,從而填充新列。

以編程方式,我們正在做的是將兩個(gè)不同的序列的 第 i 個(gè) 元素相乘,并將結(jié)果放在輸出序列的 第 i 個(gè) 位置:

一開(kāi)始,我們有以下數(shù)據(jù):

          
            Quantity = [6, 49, 27, 30, 19, 21, 12, 22, 21]
UnitPrice = [38.94, 208.16, 8.69, 195.99, 21.78, 6.64, 7.3, 42.76, 138.14]
          
        

遍歷多個(gè)列表時(shí),我們通常需要使用索引循環(huán)而不是 for-each 循環(huán):

          
            Cost = []
for i in range(len(Quantity)): # from 0 to length of Quantity-1, inclusively
    Cost.append( Quantity[i] * UnitPrice[i] )
print(Cost)

# [233.64, 10199.84, 234.63, 5879.700000000001, 413.82000000000005, 139.44, 87.6, 940.7199999999999, 2900.9399999999996]
          
        

用于組合操作的列表推導(dǎo)式

或者,更好的是,使用列表推導(dǎo)式:

          
            Cost = [Quantity[i] * UnitPrice[i] for i in range(len(Quantity))]
print(Cost)

# [233.64, 10199.84, 234.63, 5879.700000000001, 413.82000000000005, 139.44, 87.6, 940.7199999999999, 2900.9399999999996]
          
        

格式化技巧:

          
            f"{3.14159:.2f}"

# '3.14'
          
        
          
            [f"{c:.2f}" for c in Cost]

'''
['233.64',
 '10199.84',
 '234.63',
 '5879.70',
 '413.82',
 '139.44',
 '87.60',
 '940.72',
 '2900.94']
'''
          
        
          
            [round(c,2) for c in Cost]

# [233.64, 10199.84, 234.63, 5879.7, 413.82, 139.44, 87.6, 940.72, 2900.94]
          
        

請(qǐng)注意,您可能想在列表推導(dǎo)中使用兩個(gè) for 循環(huán),但是您可能獲得數(shù)量的每個(gè)值和價(jià)格的每個(gè)值的叉乘。這不是我們想要的,正如你在這里看到的:

          
            print( [q*p for q in Quantity for p in UnitPrice] ) # WRONG!

'''
[233.64, 1248.96, 52.14, 1175.94, 130.68, 39.839999999999996, 43.8, 256.56, 828.8399999999999, 1908.06, 10199.84, 425.81, 9603.51, 1067.22, 325.35999999999996, 357.7, 2095.24, 6768.86, 1051.3799999999999, 5620.32, 234.63, 5291.7300000000005, 588.0600000000001, 179.28, 197.1, 1154.52, 3729.7799999999997, 1168.1999999999998, 6244.8, 260.7, 5879.700000000001, 653.4000000000001, 199.2, 219.0, 1282.8, 4144.2, 739.8599999999999, 3955.04, 165.10999999999999, 3723.8100000000004, 413.82000000000005, 126.16, 138.7, 812.4399999999999, 2624.66, 817.74, 4371.36, 182.48999999999998, 4115.79, 457.38, 139.44, 153.29999999999998, 897.9599999999999, 2900.9399999999996, 467.28, 2497.92, 104.28, 2351.88, 261.36, 79.67999999999999, 87.6, 513.12, 1657.6799999999998, 856.68, 4579.5199999999995, 191.17999999999998, 4311.780000000001, 479.16, 146.07999999999998, 160.6, 940.7199999999999, 3039.08, 817.74, 4371.36, 182.48999999999998, 4115.79, 457.38, 139.44, 153.29999999999998, 897.9599999999999, 2900.9399999999996]
'''
          
        

zip 函數(shù)

我們也可以使用 zip ,這是一個(gè)非常有用的函數(shù),它從每個(gè)列表中提取一個(gè)值,以便在每次迭代時(shí)生成一個(gè)元組:

          
            Cost = []
for q,u in zip(Quantity,UnitPrice):
    Cost.append( q * u )
print(Cost)

# [233.64, 10199.84, 234.63, 5879.700000000001, 413.82000000000005, 139.44, 87.6, 940.7199999999999, 2900.9399999999996]
          
        

或者,使用列表推導(dǎo)式:

          
            Cost = [q * u for q,u in zip(Quantity,UnitPrice)]
print(Cost)

# [233.64, 10199.84, 234.63, 5879.700000000001, 413.82000000000005, 139.44, 87.6, 940.7199999999999, 2900.9399999999996]
          
        

分割

組合的反面是分割,我們將流拆分為兩個(gè)或更多個(gè)新的流。 例如,我經(jīng)常需要將列表中的全名拆分為它們的名字和姓氏。 在電子表格中,我們創(chuàng)建一個(gè)空白列:

然后按空格字符拆分(在 Excel 中,使用 Data > Text to Columns )獲得兩個(gè)新列:

我們可以使用 組合 操作與字符串連接運(yùn)算符“撤消”此拆分,該操作符將名字和姓氏組合成一個(gè)包含全名的新流。

拆分的另一個(gè)常見(jiàn)用途是接受表示一串?dāng)?shù)字的字符串,并將其拆分為包含這些數(shù)字的列表:

          
            '1 2 3'.split(' ')

# ['1', '2', '3']
          
        
          
            '1 2    3'.split(' ')

# ['1', '2', '', '', '', '3']
          
        
          
            values = '1 2 3'.split(' ')
[int(v) for v in values]

# [1, 2, 3]
          
        

我們甚至可以遍歷列表來(lái)獲得矩陣(列表的列表)

          
            rows = [
    '1 2 3',
    '3 4 5'
]
matrix = [[int(v) for v in row.split(' ')] for row in rows]
matrix

# [[1, 2, 3], [3, 4, 5]]
          
        
          
            from lolviz import *
objviz(matrix)
          
        

切片

到目前為止,我們檢查過(guò)的大多數(shù)操作,都會(huì)產(chǎn)生與輸入序列大小相同的列表或序列,但是有許多操作會(huì)產(chǎn)生數(shù)據(jù)的子集。第一個(gè)這樣的操作是 slice ,它提取列表的子集。(同樣,在這里我明確使用術(shù)語(yǔ)“列表”,來(lái)指示切片通常作用在適合內(nèi)存的數(shù)據(jù)結(jié)構(gòu)上。)

切片操作是兩個(gè)值的函數(shù),列表中的開(kāi)始和結(jié)束位置。

          
            names=['Xue', 'Mary', 'Bob']
print(f"Length {len(names)}")
print(names[0:1])
print(names[0:2])
print(names[0:3])
print(names[2:3])

'''
Length 3
['Xue']
['Xue', 'Mary']
['Xue', 'Mary', 'Bob']
['Bob']
'''
          
        

警告 :大多數(shù)語(yǔ)言和庫(kù)假設(shè)結(jié)束切片位置是排除的,這意味著在這種情況下切片從位置 0 到位置 3。 為了使事情變得更復(fù)雜,Python 而不是 R,從 0 開(kāi)始計(jì)數(shù)而不是 1。在這方面很難在 Python 和 R 之間來(lái)回切換,因此最好在這里強(qiáng)調(diào)一下,以便記住它。

過(guò)濾

用于從列表或序列中提取數(shù)據(jù)的最常用操作稱為 過(guò)濾 。 例如,使用 Excel 的過(guò)濾機(jī)制,我們可以對(duì) Shipping 列過(guò)濾少于 10 美元的值:

過(guò)濾操作類似于映射操作,因?yàn)橛?jì)算應(yīng)用于輸入流的每個(gè)元素。映射將一個(gè)函數(shù)應(yīng)用于序列的每個(gè)元素,并創(chuàng)建一個(gè)相同大小的新序列。過(guò)濾用特定條件測(cè)試每個(gè)元素,如果為真,則將該元素添加到新序列。

過(guò)濾操作只是一個(gè)映射,有條件地將元素添加到目標(biāo)列表:

          
            Shipping = [35, 68.02, 2.99, 3.99, 5.94, 4.95, 7.72, 6.22]
Shipping2 = []
for x in Shipping:
    if x < 10:
        Shipping2.append(x)
print(Shipping2)

# [2.99, 3.99, 5.94, 4.95, 7.72, 6.22]
          
        

用于過(guò)濾操作的列表推導(dǎo)式

但是,我們應(yīng)該使用推導(dǎo)式理解的變體,我們?cè)谟成洳僮髂J街锌吹剿?

          
            Shipping2 = [x for x in Shipping if x < 10]
print(Shipping2)

# [2.99, 3.99, 5.94, 4.95, 7.72, 6.22]
          
        

我們也可以過(guò)濾一列,但將每行中的數(shù)據(jù)保持在一起。這是一個(gè)使用 Excel 的例子,它從被提名者列表中過(guò)濾奧斯卡獲獎(jiǎng)?wù)撸l件是 winner 等于 1 ):

          
            Oscars = [
    [1984, "A Soldier's Story", 0],
    [1984, 'Places in the Heart', 0],
    [1984, 'The Killing Fields', 0],
    [1984, 'A Passage to India', 0],
    [1984, 'Amadeus', 1],
    [1985, "Prizzi's Honor", 0],
    [1985, 'Kiss of the Spider Woman', 0],
    [1985, 'Witness', 0],
    [1985, 'The Color Purple', 0],
    [1985, 'Out of Africa', 1]
]
objviz(Oscars)
          
        

循環(huán)結(jié)構(gòu)的代碼看起來(lái)像(直接跳到列表推導(dǎo)式形式):

          
            Oscars2 = [movie for movie in Oscars if movie[2]==1]
print(Oscars2)
objviz(Oscars2)

# [[1984, 'Amadeus', 1], [1985, 'Out of Africa', 1]]
          
        

輸出是列表的列表,每個(gè)電影為一行的過(guò)濾表。

注意我們?nèi)绾螠y(cè)試 movie [2] 行中的一個(gè)列值,但是將整行添加到新表中。 如果我們只是將 winner 列值添加到新列表中,我們最終會(huì)得到一個(gè)列表: 1, 1, 1, ..., 1

練習(xí)

Oscars 列表中,所有具有 3 個(gè)單詞的標(biāo)題的電影,過(guò)濾為 Oscars2 。 要將字符串分成單詞列表,請(qǐng)使用 title.split('') 。如果該列表的長(zhǎng)度“l(fā)en()”為3,則將整行復(fù)制到 Oscars2

          
            Oscars2 = [movie for movie in Oscars if len(movie[1].split(' '))==3]
print(Oscars2)

# [[1984, "A Soldier's Story", 0], [1984, 'The Killing Fields', 0], [1985, 'The Color Purple', 0], [1985, 'Out of Africa', 1]]
          
        

練習(xí)

我們還可以在列表推導(dǎo)中使用表達(dá)式,而不僅僅是引用迭代值 x 。如果少于 10 美元,請(qǐng)使用列表推導(dǎo)的過(guò)濾變體,將 Shipping 中的運(yùn)費(fèi)加倍。將結(jié)果放在列表 Shipping2 中。

          
            Shipping2 = [x*2 for x in Shipping if x < 10]
print(Shipping2)

# [5.98, 7.98, 11.88, 9.9, 15.44, 12.44]
          
        

練習(xí)

給出列表 names=['Xue', 'Mary', 'Bob'] ,對(duì)于那些以 X 開(kāi)頭的名字,將列表過(guò)濾為 names2 。 回想一下 name [i] name 中產(chǎn)生第 i 個(gè)字符。或者使用 name.startswith(...)

          
            names=['Xue', 'Mary', 'Bob']
names2 = [name for name in names if name.startswith('X')]
print(names2)

# ['Xue']
          
        

搜索

過(guò)濾操作查找序列中滿足特定條件的所有元素,但通常我們想知道哪個(gè)元素首先(或最后)滿足條件。(或者,我們通常只需要知道是否存在特定元素。)這將我們帶到 搜索 操作。最常見(jiàn)的是,搜索返回序列中的第一個(gè)(或最后一個(gè))位置,而不是該位置的值。如果我們有位置,通常稱為 索引 ,我們總是可以請(qǐng)求序列中該位置的值。如果未找到該元素,則搜索返回?zé)o效索引 -1

在某種意義上,搜索是過(guò)濾的變體。不同之處在于,我們?cè)谡业綏l件為真的元素時(shí)所做的事情。搜索不再將該元素添加到目標(biāo)列表中,而是退出循環(huán)。

          
            first=['Xue', 'Mary', 'Robert']     # our given input
target = 'Mary'                     # searching for Mary
index = -1
for i in range(len(first)):         # i is in range [0..n-1] or [0..n)
    if first[i]==target:
        index = i
        break
print(index)

# 1
          
        

無(wú)論循環(huán)類型如何, break 語(yǔ)句都會(huì)打破閉合的循環(huán)。

搜索操作甚至可以在字符串(字符列表)中使用,來(lái)找到感興趣字符的位置。 例如,要將全名切割為名字和姓氏,我們可以將搜索空格字符與兩個(gè)切片操作組合在一起。 給定全名 Xue Li ,搜索空格字符將返回第四個(gè)位置或索引 3。要提取第一個(gè)名稱,我們將從索引 0 切片到索引 3,僅排除右側(cè)。 為了獲得姓氏,我們從索引 4 切換到 6,僅排除右側(cè)。

這就是 python 的樣子:

          
            name = 'Xue Li'

# SEARCH
index = -1
for i in range(len(name)):
    if name[i]==' ':
        index = i
        break
print(f"Index of space is {index}")

# SLICE
print(f"First: {name[0:index]}")
print(f"Last: {name[index+1:]}") # or name[index+1:len(name)]

'''
Index of space is 3
First: Xue
Last: Li
'''
          
        

為了確定字符串結(jié)尾的索引,程序員傾向于使用字符串的長(zhǎng)度。長(zhǎng)度可以是一個(gè)索引,其值是字符串末尾的后一個(gè)值,這是使用排除性右索引時(shí),我們想要用于切片的。

嵌套循環(huán)

我們有時(shí)需要重復(fù)重復(fù)的指令,我們稱之為 嵌套循環(huán) 。在分析領(lǐng)域,嵌套循環(huán)非常重要,因?yàn)槲覀兪褂们短籽h(huán)來(lái)處理矩陣,圖像和數(shù)據(jù)表。

處理矩陣

回想一下,雖然我們?nèi)祟惪梢酝瑫r(shí)查看整個(gè)矩陣,但計(jì)算機(jī)會(huì)逐個(gè)檢查每個(gè)元素。 看看這個(gè) 3x3 矩陣:

我們可以使用列表的列表在 python 中表示:

          
            A = [
    [1, 3, 10],
    [4, -9, 0],
    [2, 5, 8]
]
          
        

因?yàn)檫@不是一維數(shù)據(jù)結(jié)構(gòu),所以我們不能使用簡(jiǎn)單的“對(duì)于矩陣中的每個(gè)元素”循環(huán)來(lái)檢查每個(gè)元素。 迭代 nrows x ncols 矩陣的所有元素的最常見(jiàn)模式如下所示:

          
            for i in 0..nrows-1:
    for j in 0..ncols-1:
        do something with matrix[i,j]
          
        

其中 matrix[i, j] 訪問(wèn)行 i 和列 j 的元素。 這樣的嵌套循環(huán)給出了 i j 的所有可能組合,這是我們?cè)诰仃嚿喜僮鲿r(shí)所需要的。考慮以下該模板到 Python 的轉(zhuǎn)換,打印出所有二維索引:

          
            nrows = 3  # or len(A)
ncols = 3  # or len(A[0]) length of first row
for i in range(nrows):
    for j in range(ncols):
        print( i, j )
        
'''
0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
'''
          
        

注意列 j 值如何比行 i 值變化得更快。我們可以通過(guò)改變循環(huán)次序來(lái)反轉(zhuǎn)這種遍歷順序:

          
            for j in range(ncols):
    for i in range(nrows):
        print(i, j)
'''
0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
'''
          
        

j 循環(huán)在外部,它的變化速度比內(nèi)部 i 循環(huán)慢。

用于獲得所有組合的雙重 for 列表推導(dǎo)

列表推導(dǎo)中的雙重循環(huán)給出了所有組合,在這種情況下是我們想要的。以下代碼示例創(chuàng)建坐標(biāo)的字符串表示的列表:

          
            coords = [f"{i},{j}" for i in range(nrows) for j in range(ncols)]
print(coords)

# ['0,0', '0,1', '0,2', '1,0', '1,1', '1,2', '2,0', '2,1', '2,2']
          
        

現(xiàn)在,讓我們使用累加器來(lái)求和 3x3 矩陣的所有元素,我們讓 nrows = 3 ncols = 3 并使用加法運(yùn)算:

          
            sum = 0
for i in range(nrows):
    for j in range(ncols):
        sum = sum + A[i][j]
print(sum)

# 24
          
        

處理圖像

在這個(gè)課程的圖像項(xiàng)目中,我們?yōu)閳D像做了很多有趣的事情。 圖像只不過(guò)是二維矩陣,其條目是從 0 到 255 的像素灰度值。像素值 0 是黑色而 255 是白色。 例如,如果我們放大圖像,我們會(huì)看到二維矩陣的各個(gè)元素(稱為像素):

圖像和矩陣之間的唯一區(qū)別是,我們通常使用 x y 坐標(biāo)而不是行和列來(lái)訪問(wèn)圖像的元素。訪問(wèn)圖像的每個(gè)元素的嵌套循環(huán)的模板如下所示:

          
            for x in 0..width-1:
    for y in 0..height-1:
        process pixel[x,y]
          
        

由于 y 坐標(biāo)的變化快于 x 坐標(biāo),因此內(nèi)部循環(huán)遍歷垂直條形。外部循環(huán)將 x 移動(dòng)到右邊的下一個(gè)垂直條紋。

練習(xí)

作為一個(gè)更現(xiàn)實(shí)的例子,讓我們將兩個(gè)矩陣 A B 相加為 C 。關(guān)鍵操作是將 A[i,j] 加上 B[i,j] 來(lái)獲得 C[i,j] 。 在視覺(jué)上,它看起來(lái)像這樣:

寫(xiě)出嵌套的 Python 索引循環(huán),將兩個(gè)矩陣相加, C = A + B 。這里有一些定義可以幫助您入門(mén):

          
            nrows = ncols = 3
A = [
    [1, 3, 10],
    [4, -9, 0],
    [2, 5, 8]
]
B = [
    [7, 4, 0],
    [4, 3, 1],
    [1, 6, 8]
]
# Use list comprehension to init list of lists
C = [[0]*ncols for i in range(nrows)]
          
        
          
            A = [
    [1, 3, 10],
    [4, -9, 0],
    [2, 5, 8]
]
B = [
    [7, 4, 0],
    [4, 3, 1],
    [1, 6, 8]
]
# Use list comprehension to init list of lists
C = [[0]*ncols for i in range(nrows)]
for i in range(nrows):
    for j in range(ncols):
        C[i][j] = A[i][j] + B[i][j]
print(C)

# [[8, 7, 10], [8, -6, 1], [3, 11, 16]]
          
        
          
            import numpy as np
np.array(A) + np.array(B)

'''
array([[ 8,  7, 10],
       [ 8, -6,  1],
       [ 3, 11, 16]])
'''
          
        

警告:不要這樣做:

          
            D=[[0]*ncols]*nrows
objviz(D)
          
        

          
            D[0][1] = 3
D

# [[0, 3, 0], [0, 3, 0], [0, 3, 0]]
          
        
          
            # compare to this:
objviz([[0]*ncols for i in range(nrows)])
          
        

練習(xí)

我們也可以使用嵌套 for-each 循環(huán),而不是使用索引循環(huán)(這非常適合于矩陣),像我們迄今為止所做的那樣。 試試吧。

給出一個(gè)名字列表, first=['Xue', 'Mary', 'Robert'] 和姓氏列表, last=['Li', 'Smith', 'Dixon'] ,寫(xiě) 一個(gè)嵌套的 Python 循環(huán),用于打印名字和姓氏的每個(gè)組合。

          
            first=['Xue', 'Mary', 'Robert']
last=['Li', 'Smith', 'Dixon']
for f in first:
    for l in last:
        print(f+' '+l)
        
'''
Xue Li
Xue Smith
Xue Dixon
Mary Li
Mary Smith
Mary Dixon
Robert Li
Robert Smith
Robert Dixon
'''
          
        

練習(xí)

現(xiàn)在使用雙重循環(huán)列表推導(dǎo)式重復(fù)該練習(xí)。

          
            print([f+' '+l for f in first for l in last])

# ['Xue Li', 'Xue Smith', 'Xue Dixon', 'Mary Li', 'Mary Smith', 'Mary Dixon', 'Robert Li', 'Robert Smith', 'Robert Dixon']
          
        

更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产91在线chines看 | 日韩欧美中文字幕在线视频 | 日本精品一区 | 毛片视频播放 | 久热这里只有精品视频6 | 99re国产精品视频首页 | 午夜欧美在线 | 四虎影院免费观看视频 | 国产臀控福利视频在线 | 国产精品久久久久久 | 特级全黄一级毛片免费 | 亚洲国产精品一区二区第四页 | 亚洲国产爱久久全部精品 | 一本久道久久综合狠狠爱 | 日本成本人在线观看免费视频 | 国产精品品福利视频 | 一国产大片在线观看 | 99久久亚洲国产高清观看 | 九九九热在线精品免费全部 | 一a一片一级一片啪啪 | 成人在线a | 精品视频在线观看一区二区三区 | 天天看天天爽 | 国产免费一区二区三区 | 久久精品大片 | 欧洲老妇bbbbbxxxxx | 久久一er精这里有精品 | 日本高清中文字幕一区二区三区 | 国产精品久久久久久亚洲伦理 | 国产精品久久亚洲一区二区 | 色涩网站在线观看 | 欧美黑人喷潮水xxxx | 日本毛片在线观看 | 国产精品久久亚洲不卡动漫 | 日韩国产成人资源精品视频 | 91精品国产色综合久久不卡蜜 | 夜夜操夜夜摸 | 中文字幕精品在线视频 | 国产资源福利 | 亚洲一区二区三区影院 | 四虎在线免费观看 |