1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        4300 字Python列表使用總結(jié),用心!

        共 4591字,需瀏覽 10分鐘

         ·

        2020-08-28 09:15


        來自公眾號:Python與算法社區(qū)

        今天列表專題的目錄如下:

        列表基礎(chǔ)

          • 1 創(chuàng)建列表

          • 2 訪問元素

          • 3 添加元素

          • 4 刪除元素

          • 5 list 與 in

          • 6 list 與數(shù)字

          • 7 列表生成式

        • 列表進階

          • 8 其他常用API

          • 9 列表實現(xiàn)棧

          • 10 列表包含自身

          • 11 插入元素性能分析

          • 12 深淺拷貝

          • 13 列表可變性

        列表基礎(chǔ)

        1 創(chuàng)建列表

        列表是一個容器,使用一對中括號[]創(chuàng)建一個列表。

        創(chuàng)建一個空列表:

        a?=?[]?#?空列表

        創(chuàng)建一個含有 5 個整型元素的列表a

        a?=?[3,7,4,2,6]

        列表與我們熟知的數(shù)組很相似,但又有很大區(qū)別。

        一般數(shù)組內(nèi)的元素要求同一類型,但是列表內(nèi)可含有各種不同類型,包括再嵌套列表。

        如下,列表a包含三種類型:整形,字符串,浮點型:

        如下列表a嵌套兩個列表:

        2 訪問元素

        列表訪問主要包括兩種:索引和切片。

        如下,訪問列表a可通過我們所熟知的正向索引,注意從0開始;

        也可通過Python特有的負向索引,

        即從列表最后一個元素往前訪問,此時索引依次被標(biāo)記為-1,-2,...,-5 ,注意從-1開始。

        除了以上通過索引訪問單個元素方式外,

        還有非常像matlab的切片訪問方式,這是一次訪問多個元素的方法。

        切片訪問的最基本結(jié)構(gòu):中間添加一個冒號。

        如下切片,能一次實現(xiàn)訪問索引為1到4,不包括4的序列:

        In?[1]:?a=[3,7,4,2,6]

        In?[2]:?a[1:4]
        Out[2]:?[7,?4,?2]

        Python支持負索引,能帶來很多便利。比如能很方便的獲取最后三個元素:

        In?[1]:?a=[3,7,4,2,6]

        In?[3]:?a[-3:]
        Out[3]:?[4,?2,?6]

        除了使用一個冒號得到連續(xù)切片外,

        使用兩個冒號獲取帶間隔的序列元素,兩個冒號后的數(shù)字就是間隔長度:

        In?[1]:?a=[3,7,4,2,6]

        In?[7]:?a[::2]?#?得到切片間隔為2
        Out[7]:?[3,?4,?6]

        其實最全的切片結(jié)構(gòu):start:stop:interval,如下所示,獲得切片為:索引從15間隔為2:

        In?[6]:?a=[3,7,4,2,6]

        In?[7]:?a[1:5:2]
        Out[7]:?[7,?2]

        3 添加元素

        列表與數(shù)組的另一個很大不同,使用數(shù)組前,需要知道數(shù)組長度,便于從系統(tǒng)中申請內(nèi)存。

        但是,列表卻不需要預(yù)先設(shè)置元素長度。

        它支持任意的動態(tài)添加元素,完全不用操心列表長短。

        它會隨著數(shù)組增加或刪除而動態(tài)的調(diào)整列表大小。

        這與數(shù)據(jù)結(jié)構(gòu)中的線性表或向量很相似。

        添加元素通常有兩類場景。

        append一次添加1個元素,insert在指定位置添加元素:

        In?[8]:?a=[3,7,4,2,6]
        In?[9]:?a.append(1)?#?append默認在列表尾部添加元素
        In?[10]:?a
        Out[10]:?[3,?7,?4,?2,?6,?1]

        In?[11]:?a.insert(2,5)?#?insert?在索引2處添加元素5
        In?[12]:?a
        Out[12]:?[3,?7,?5,?4,?2,?6,?1]

        extend或直接使用+實現(xiàn)一次添加多個元素:

        In?[13]:?a.extend([0,10])#?一次就地添加0,10兩個元素
        In?[14]:?a
        Out[14]:?[3,?7,?5,?4,?2,?6,?1,?0,?10]

        In?[15]:?b?=?a+[11,21]?#?+?不是就地添加,而是重新創(chuàng)建一個新的列表
        In?[16]:?b
        Out[16]:?[3,?7,?5,?4,?2,?6,?1,?0,?10,?11,?21]

        這里面有一個重要細節(jié),不知大家平時注意到嗎。

        extend 方法實現(xiàn)批量添加元素時未創(chuàng)建一個新的列表,而是直接添加在原列表中,這被稱為in-place,就地。而b=a+list對象實際是創(chuàng)建一個新的列表對象,所以不是就地批量添加元素。

        但是,a+=一個列表對象,+=操作符則就會自動調(diào)用extend方法進行合并運算。大家注意這些微妙的區(qū)別,不同場景選用不同的API,以此高效節(jié)省內(nèi)存。

        4 刪除元素

        刪除元素的方法有三種:remove,pop,del.

        remove直接刪除元素,若被刪除元素在列表內(nèi)重復(fù)出現(xiàn)多次,則只刪除第一次:

        In?[17]:?a=[1,2,3,2,4,2]
        In?[18]:?a.remove(2)
        In?[19]:?a
        Out[19]:?[1,?3,?2,?4,?2]

        pop方法若不帶參數(shù)默認刪除列表最后一個元素;若帶參數(shù)則刪除此參數(shù)代表的索引處的元素:

        In[19]:?a?=?[1,?3,?2,?4,?2]
        In?[20]:?a.pop()?#?刪除最后一個元素
        Out[20]:?2
        In?[21]:?a
        Out[21]:?[1,?3,?2,?4]

        In?[22]:?a.pop(1)?#?刪除索引等于1的元素
        Out[22]:?3
        In?[23]:?a
        Out[23]:?[1,?2,?4]

        delpop相似,刪除指定索引處的元素:

        In?[24]:?a?=?[1,?2,?4]
        In?[25]:?del?a[1:]?#?刪除索引1到最后的切片序列
        In?[26]:?a
        Out[26]:?[1]

        5 list 與 in

        列表是可迭代的,除了使用類似c語言的索引遍歷外,還支持for item in alist這種直接遍歷元素的方法:

        In?[28]:?a?=?[3,7,4,2,6]
        In?[29]:?for?item?in?a:
        ????...:?????print(item)
        3
        7
        4
        2
        6

        in 與可迭代容器的結(jié)合,還用于判斷某個元素是否屬于此列表:

        In?[28]:?a?=?[3,7,4,2,6]
        In?[30]:?4?in?a
        Out[30]:?True

        In?[31]:?5?in?a
        Out[31]:?False

        6 list 與數(shù)字

        內(nèi)置的list與數(shù)字結(jié)合,實現(xiàn)元素的復(fù)制,如下所示:

        In?[32]:?['Hi!']?*?4
        Out[32]:?['Hi!',?'Hi!',?'Hi!',?'Hi!']

        表面上這種操作太方便,實際確實也很方便,比如我想快速打印20個-,只需下面一行代碼:

        In?[33]:?'-'*20
        Out[33]:?'--------------------'

        使用列表與數(shù)字相乘構(gòu)建二維列表,然后第一個元素賦值為[1,2],第二個元素賦值為[3,4],第三個元素為[5]

        In?[34]:?a?=?[[]]?*?3
        In?[35]:?a[0]=[1,2]
        In?[36]:?a[1]=[3,4]
        In?[37]:?a[2]=[5]
        In?[38]:?a
        Out[38]:?[[1,?2],?[3,?4],?[5]]

        7 列表生成式

        列表生成式是創(chuàng)建列表的一個方法,它與使用append等API創(chuàng)建列表相比,書寫更加簡潔。

        使用列表生成式創(chuàng)建1到50的所有奇數(shù)列表:

        a=[i?for?i?in?range(50)?if?i&1]

        列表進階

        8 其他常用API

        除了上面提到的方法外,列表封裝的其他方法還包括如下:

        clear,index,count,sort,reverse,copy

        clear 用于清空列表內(nèi)的所有元素index 用于查找里面某個元素的索引:

        In?[4]:?a=[1,3,7]

        In?[5]:?a.index(7)
        Out[5]:?2

        count 用于統(tǒng)計某元素的出現(xiàn)次數(shù):

        In?[6]:?a=[1,2,3,2,2,5]

        In?[7]:?a.count(2)?#?元素2出現(xiàn)3次
        Out[7]:?3

        sort 用于元素排序,其中參數(shù)key定制排序規(guī)則。如下列表,其元素為元祖,根據(jù)元祖的第二個值由小到大排序:

        In?[8]:?a=[(3,1),(4,1),(1,3),(5,4),(9,-10)]

        In?[9]:?a.sort(key=lambda?x:x[1])

        In?[10]:?a
        Out[10]:?[(9,?-10),?(3,?1),?(4,?1),?(1,?3),?(5,?4)]

        reverse 完成列表反轉(zhuǎn):

        In?[15]:?a=[1,3,-2]

        In?[16]:?a.reverse()

        In?[17]:?a
        Out[17]:?[-2,?3,?1]

        copy 方法在下面講深淺拷貝時會詳細展開。

        9 列表實現(xiàn)棧

        列表封裝的這些方法,實現(xiàn)這個常用的數(shù)據(jù)結(jié)構(gòu)比較容易。棧是一種只能在列表一端進出的特殊列表,pop方法正好完美實現(xiàn):

        In?[23]:?stack=[1,3,5]

        In?[24]:?stack.append(0)?#?push元素0到尾端,不需要指定索引

        In?[25]:?stack
        Out[25]:?[1,?3,?5,?0]

        In?[26]:?stack.pop()?#?pop元素,不需指定索引,此時移出尾端元素
        Out[26]:?0

        In?[27]:?stack
        Out[27]:?[1,?3,?5]

        由此可見Python的列表當(dāng)做棧用,完全沒有問題,push 和 pop 操作的時間復(fù)雜度都為 O(1)

        但是使用列表模擬隊列就不那么高效了,需要借助Python的collections模塊中的雙端隊列deque實現(xiàn)。

        10 列表包含自身

        列表的賦值操作,有一個非常有意思的問題,大家不妨耐心看一下。

        In?[1]:?a=[1,3,5]

        In?[2]:?a[1]=a??#?列表內(nèi)元素指向自身

        這樣相當(dāng)于創(chuàng)建了一個引用自身的結(jié)構(gòu)。

        打印結(jié)果顯示是這樣的:

        In?[3]:?a
        Out[3]:?[1,?[...],?5]

        中間省略號表示無限循環(huán),這種賦值操作導(dǎo)致無限循環(huán),這是為什么?下面分析下原因。

        執(zhí)行 a = [1,3,5] 的時候,Python 做的事情是首先創(chuàng)建一個列表對象 [1, 3, 5],然后給它貼上名為a的標(biāo)簽。

        執(zhí)行 a[1] = a 的時候,Python 做的事情則是把列表對象的第二個元素指向a所引用的列表對象本身。

        執(zhí)行完畢后,a標(biāo)簽還是指向原來的那個對象,只不過那個對象的結(jié)構(gòu)發(fā)生了變化。

        從之前的列表 [1,3,5] 變成了 [1,[...], 5],而這個[...]則是指向原來對象本身的一個引用。

        如下圖所示:

        可以看到形成一個環(huán)路:a[1]--->中間元素--->a[1],所以導(dǎo)致無限循環(huán)。

        11 插入元素性能分析

        與常規(guī)數(shù)組需要預(yù)先指定長度不同,Python 中l(wèi)ist不需要指定容器長度,允許我們隨意的添加刪除元素。

        但是這種便捷性也會帶來一定副作用,就是插入元素的時間復(fù)雜度為O(n),而不是O(1),因為insert會導(dǎo)致依次移動插入位置后的所有元素。

        為了加深對插入元素的理解,特意把cpython實現(xiàn)insert元素的操作源碼拿出來。

        可以清楚看到insert元素時,插入位置處的元素都會后移一個位置,因此插入元素的時間復(fù)雜為O(n),所以凡是涉及頻繁插入刪除元素的操作,都不太適合用list.

        static?int
        ins1(PyListObject?*self,?Py_ssize_t?where,?PyObject?*v)
        {
        ????assert((size_t)n?+?1?????if?(list_resize(self,?n+1)?0)
        ????????return?-1;

        ????if?(where?0)?{
        ????????where?+=?n;
        ????????if?(where?0)
        ????????????where?=?0;
        ????}
        ????if?(where?>?n)
        ????????where?=?n;
        ????items?=?self->ob_item;
        ????//依次移動插入位置后的所有元素
        ????//?O(n)?時間復(fù)雜度
        ????for?(i?=?n;?--i?>=?where;?)?
        ????????items[i+1]?=?items[i];
        ????Py_INCREF(v);
        ????items[where]?=?v;
        ????return?0;
        }

        12 深淺拷貝

        list 封裝的copy 方法實現(xiàn)對列表的淺拷貝,淺拷貝只拷貝一層,具體拿例子說:

        In?[38]:?c?=[1,3,5]

        In?[39]:?cc?=?c.copy()

        ccc分別指向一片不同內(nèi)存,示意圖如下:

        這樣修改cc的第一個元素,原來c不受影響:

        In?[40]:?cc[0]=10?#?修改cc第一個元素

        In?[41]:?cc
        Out[41]:?[10,?3,?5]

        In?[42]:?c?#?原來?c?不受影響
        Out[42]:?[1,?3,?5]

        但是,如果內(nèi)嵌一層列表,再使用copy時只拷貝一層:

        In?[32]:?a=[[1,3],[4,2]]

        In?[33]:?ac?=?a.copy()

        In?[34]:?ac
        Out[34]:?[[1,?3],?[4,?2]]

        上面的示意圖清晰的反映出這一點,內(nèi)嵌的列表并沒有實現(xiàn)拷貝。因此再修改內(nèi)嵌的元素時,原來的列表也會受到影響。

        In?[35]:?ac[0][0]=10

        In?[36]:?ac
        Out[36]:?[[10,?3],?[4,?2]]

        In?[37]:?a
        Out[37]:?[[10,?3],?[4,?2]]

        要想實現(xiàn)深度拷貝,需要使用Python模塊copy中的deepcopy方法。

        13 列表可變性

        列表是可變的,可變的對象是不可哈希的,不可哈希的對象不能被映射,因此不能被用作字典的鍵。

        In?[51]:?a=[1,3]
        In?[52]:?d={a:'不能被哈希'}?#會拋出如下異常

        #?TypeError:?unhashable?type:?'list'

        但是,有時我們確實需要列表對象作為鍵,這怎么辦?

        可以將列表轉(zhuǎn)化為元祖,元祖是可哈希的,所以能作為字典的鍵。

        總結(jié)

        以上就是列表專題的所有13個方面總結(jié),目錄如下:

        瀏覽 116
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            天天日夜夜抽 | 娇妻乳峰乱颤娇喘连连 | 天堂AV√| 自拍第一页 | 美女高清毛片 | www.艹艹艹 | 三级片影音先锋 | 张筱雨下面粉嫩水又多 | 日本天堂网 | 性生交大片免费视频法国 |