操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    我們在這個系列的開篇有提到,所謂的編程,其實就兩個核心,一個是數據的表達,一個是數據的處理。

    前面連著分享了幾篇關于函數的文章,主要是聚焦的數據的處理。Python中一切皆對象,其實是一種設計思想,將數據的表達與數據的處理封裝在一起。

    從今天開始,打算通過幾篇文章,來重點介紹下Python中關于數據表達的部分,用計算機專業的術語來說,就是“數據結構”。

    在編程中,最常用的數據結構,主要有數組、鏈表、字典、集合等。

    Python中內置的對應實現有:列表(list)、元組(tuple)、字典(dict)、集合(set)等,還包括一些其他模塊中更好用的容器類,在后面的幾篇文章中都會陸續進行介紹,今天這篇文章,首先來看一下Python中的列表(list)。

    需要說明的是,有的地方把這些數據結構稱為集合的操作,有些地方又稱為容器對象。為了避免與set的集合的含義的混淆,我這里統一稱為容器對象了。

    Python中列表的特點

    Python中的列表,是一個非常強大的數據結構,具有很多顯著的特點。用一句話來形容Python的列表的話,就是“Great Actor”(特別能裝)。因為不同于其他編程語言中類似的數據結構,Python中的列表,可以存儲任意類型的數據元素。除了特別能裝外,列表的主要特點如下:
    1、可變性(Mutable):列表是可變的,可以進行增、刪、改的操作;
    2、有序性(Ordered):列表中的元素是有序的;
    3、支持任意類型:不要求元素類型一致,這是跟其他編程語言尤其是靜態類型語言中數據結構的不同點;
    4、可以動態調整大?。焊鶕嶋H的需要,自動進行長度的縮減;
    5、提供了豐富的內置方法:如增加、刪除、排序等

    list的常用內置方法

    通過查看list的定義,可以看到list所支持的內置方法清單。這里,不再進行一一列舉,感興趣的童鞋可以自行查看。

    這里只對常用的一些方法做一下簡要說明:

    # 創建一個空列表
    great_box=[]
    print(great_box)
    
    # 尾部追加一個字符串
    great_box.append('Python')
    print(great_box)
    
    # index為0的位置插入一個字符串
    great_box.insert(0, 'Java')
    print(great_box)
    
    # 追加一個list對象作為元素
    great_box.append([1, 2, 3])
    print(great_box)
    
    # 將一個元組的元素分別添加到列表中
    # 各種類型都可以
    great_box.extend((tuple(), list(), {}))
    print(great_box)
    
    # 默認把尾部的元素移除(彈出)
    great_box.pop()
    print(great_box)
    
    # 彈出指定索引的元素
    res=great_box.pop(1)
    print(res)
    print(great_box)
    
    # 列表元素逆序,原地修改,也就是改變原對象
    great_box.reverse()
    print(great_box)
    
    # 獲取元素個數,內置函數len()
    print(len(great_box))
    
    

    執行結果:

    可以看到,這些方法跟其他編程語言中也都是比較類似的。

    接下來,以幾個實際場景,演示list的使用。

    對列表進行排序

    對數據的排序應該是數據處理中,一個特別常用的操作。雖然,我們不需要自己編寫排序算法,但是很多方法的底層,也會用到排序。

    Python中對列表中的元素進行排序,有兩種常見的方法:

    方法1:列表的方法(進行原地修改(in place))

    import random
    # 隨機生成一組身高數據,保存到列表heights中
    heights=[]
    for _ in range(10):
        heights.append(random.randint(140, 200))
    print('='*22 + '原始順序' + '='*22)
    print(heights)
    # 原地排序操作,默認升序
    print('='*22 + '升序排序' + '='*22)
    heights.sort()
    print(heights)
    # 降序排列
    print('='*22 + '降序排序' + '='*22)
    heights.sort(reverse=True)
    print(heights)
    
    

    執行結果:

    上面這個例子,其實沒有任何實際的價值,我們在大多數場景中,不會只有一個列表存儲了身高,而沒有其他信息。
    通常來說,會把人員的相關信息一起存儲,我們需要按照身高排序,或者按照年齡排序,sort()方法其實也是可以支持的,可以對照list的sort()方法的定義來看:

    from faker import Faker
    
    fk=Faker('zh_CN')
    
    persons=[]
    for _ in range(10):
        # 以元組形式存儲人員信息(姓名,年齡,身高)
        persons.append((fk.name(), fk.random_int(10, 150), fk.random_int(140, 200)))
    print('=' * 22 + '原始順序' + '=' * 22)
    print(persons)
    
    print('=' * 22 + '按照年齡升序' + '=' * 22)
    persons.sort(key=lambda x: x[1])
    print(persons)
    
    print('=' * 22 + '按照身高降序' + '=' * 22)
    persons.sort(key=lambda x: x[2], reverse=True)
    print(persons)
    
    

    執行結果:

    方法2:使用內置函數sorted()
    需要注意的是,不同于列表對象的sort()方法,sorted()函數并不會在原地排序,也就是不會改變原列表對象,而是通過函數返回值,返回排序之后的新的列表對象:

    from faker import Faker
    
    fk=Faker('zh_CN')
    
    persons=[]
    for _ in range(10):
        # 以元組形式存儲人員信息(姓名,年齡,身高)
        persons.append((fk.name(), fk.random_int(10, 150), fk.random_int(140, 200)))
    print('=' * 22 + '原始順序' + '=' * 22)
    print(persons)
    
    print('=' * 22 + '按照年齡升序' + '=' * 22)
    # persons.sort(key=lambda x: x[1])
    new_persons=sorted(persons, key=lambda x: x[1])
    print(new_persons)
    
    print('=' * 22 + '按照身高降序' + '=' * 22)
    # persons.sort(key=lambda x: x[2], reverse=True)
    new_persons=sorted(persons, key=lambda x: x[2], reverse=True)
    print(persons)
    
    

    執行結果:

    可以看到,唯一的不同,是否原地修改的。

    如何判定元素是否存在

    在Python中,使用in、not in操作符,可以很便捷地判定元素在列表對象中是否存在:

    languages=['Python', 'Java', 'Go']
    if 'Python' in languages:
        print('Python exists')
    if 'C++' not in languages:
        print('C++ not exists')
    
    

    執行結果:

    如何檢索特定元素

    在Python中,可以通過列表對象的index()方法,快速找到某個特定元素在列表中的位置。
    需要注意的是,如果元素出現多次,會返回第一個索引;如果元素不存在,會拋異常。

    languages=['Python', 'Java', 'Go', 'Java']
    print(languages)
    idx=languages.index('Java')
    print(idx)
    idx=languages.index('C++')
    print(idx)
    
    

    執行結果:

    列表推導式

    前面我們通過for循環的方式,將元素逐個追加到列表中,其實,是有些繁瑣的。還是那句話,“能用一行代碼搞定的事,絕對不寫兩行”。

    Python中提供列表推導式的語法,幫助我們簡化列表對象的構建:
    還是以測試人員信息的列表生成為例,我們使用列表推導式來改寫:

    from faker import Faker
    
    fk=Faker('zh_CN')
    
    # persons=[]
    # for _ in range(10):
    #     # 以元組形式存儲人員信息(姓名,年齡,身高)
    #     persons.append((fk.name(), fk.random_int(10, 150), fk.random_int(140, 200)))
    
    persons=[(fk.name(), fk.random_int(10, 150), fk.random_int(140, 200)) for _ in range(10)]
    
    

    注釋的三行代碼,使用列表推導式,只需要一行代碼就搞定了。
    剛開始接觸列表推導式,可能不太習慣,但是用得多了,你一定會被這種簡潔性所征服,不由自主地選擇使用列表推導式。
    除了列表的生成可以使用列表推導式外,字典、集合同樣支持推導式的快速生成。

    此外,“Python一行流”的很多代碼編寫方法也是基于推導式的方式來加以實現的。

    總結

    本文簡單介紹了Python中的列表這個容器類型,包括常用的內置方法以及列表推導式的使用。列表的靈活性,配合列表推導式的簡潔性,在實際的Python編程實踐中非常實用,掌握了列表的使用,一定能大大提升Python開發的效率。

    創建容器視圖的范圍

    新的范圍庫是 C++20 中更重要的新增內容之一。它為過濾和處理容器提供了一種新的范式。范圍提供了干凈直觀的構建塊,使得代碼更有效、更易讀。

    讓我們首先定義一些術語:

    一個范圍是可以迭代的對象集合。換句話說,任何支持 begin() 和 end() 迭代器的結構都是一個范圍。這包括大多數 STL 容器。

    視圖是一個轉換另一個底層范圍的范圍。視圖是惰性的,這意味著它們只在范圍迭代時操作。視圖返回底層范圍的數據,本身不擁有任何數據。視圖以 O(1) 常數時間操作。

    視圖適配器是一個對象,它接受一個范圍并返回一個視圖對象。視圖適配器可以使用 | 運算符與其他視圖適配器鏈式使用。

    注意

    <ranges> 庫使用 std::ranges 和 std::ranges::view 名稱空間。認識到這很笨重,標準包括一個別名 std::ranges::view 作為簡單的 std::view。我覺得這仍然很笨重。對于這個食譜,我將使用以下別名,以節省空間,因為我覺得它更優雅:

    namespace ranges=std::ranges;  // 節省手指!
    
    namespace views=std::ranges::views;


    這適用于這個食譜中的所有代碼。

    如何做到這一點…

    范圍和視圖類在 <ranges> 頭文件中。讓我們看看你如何使用它們:

    視圖應用于范圍,如下所示:

    const vector<int> nums{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    auto result=ranges::take_view(nums, 5);
    
    for (auto v: result) cout << v << " ";


    輸出:

    1 2 3 4 5


    ranges::take_view(range, n) 是一個返回前 n 個元素的視圖。

    你也可以使用 take_view() 的視圖適配器版本:

    auto result=nums | views::take(5);
    for (auto v: result) cout << v << " ";


    輸出:

    1 2 3 4 5


    視圖適配器在 std::ranges::views 名稱空間中。視圖適配器從 | 運算符左側的 range 操作數中獲取范圍,很像 iostreams 使用 << 運算符的方式。| 運算符是從左到右評估的。

    因為視圖適配器是可迭代的,它也符合范圍的資格。這允許它們被連續應用,如下所示:

    const vector<int> nums{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    auto result=nums | views::take(5) |
       views::reverse;


    輸出:

    5 4 3 2 1


    filter() 視圖使用謂詞函數:

    auto result=nums |
        views::filter([](int i){ return 0==i % 2; });


    輸出:

    2 4 6 8 10

    transform() 視圖使用轉換函數:

    auto result=nums |
        views::transform([](int i){ return i * i; });


    輸出:

    1 4 9 16 25 36 49 64 81 100


    當然,這些視圖和適配器適用于任何類型的范圍:

    cosnt vector<string> words{ "one", "two", "three", "four", "five" };
    auto result=words | views::reverse;


    輸出:

    five four three two one


    范圍庫還包括一些范圍工廠。iota 工廠將生成一系列遞增的值:

    auto rnums=views::iota(1, 10);


    輸出:

    1 2 3 4 5 6 7 8 9


    iota(value, bound) 函數從 value 開始生成一個序列,結束在 bound 之前。如果省略了 bound,序列就是無限的:

    auto rnums=views::iota(1) | views::take(200);


    輸出:

    1 2 3 4 5 6 7 8 9 10 11 12 […] 196 197 198 199 200


    范圍、視圖和視圖適配器非常靈活和有用。讓我們更深入地了解,以更好地理解。

    它是如何工作的…

    為了滿足范圍的基本要求,一個對象必須至少有兩個迭代器,begin() 和 end(),其中 end() 迭代器是一個哨兵,用于確定范圍的終點。大多數 STL 容器都符合范圍的要求,包括 string、vector、array、map 等,值得注意的例外是容器適配器,如 stack 和 queue,它們沒有 begin 和 end 迭代器。

    視圖是一個操作范圍并返回修改后范圍的對象。視圖惰性操作,并且不包含自己的數據。它不保留底層數據的副本,而是根據需要簡單地返回指向底層元素的迭代器。讓我們檢查這段代碼片段:

    vector<int> vi { 0, 1, 2, 3, 4, 5 };
    ranges::take_view tv{vi, 2};
    for(int i : tv) {
        cout << i << " ";
    }
    cout << "\n";


    輸出:

    0 1


    在這個例子中,take_view 對象接受兩個參數,一個范圍(在這種情況下,一個 vector<int> 對象)和一個計數。結果是從向量中取出前計數個對象的視圖。在評估時,在 for 循環迭代期間,take_view 對象簡單地根據需要返回指向向量對象元素的迭代器。在這個過程中,向量對象沒有被修改。

    范圍名稱空間中的許多視圖在 views 名稱空間中都有相應的范圍適配器。這些適配器可以使用按位或 (|) 運算符使用,像這樣:

    vector<int> vi { 0, 1, 2, 3, 4, 5 };
    ranges::take_view tv{vi, 2};
    for(int i : tv) {
        cout << i << " ";
    }
    cout << "\n";


    輸出:

    0 1


    正如預期的那樣,| 運算符從左到右評估。由于范圍適配器的結果又是另一個范圍,這些適配器表達式可以被鏈接:

    vector<int> vi { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    auto tview=vi | views::reverse | views::take(5);
    for(int i : tview) {
        cout << i << " ";
    }
    cout << "\n";


    輸出:

    9 8 7 6 5


    庫中還包括一個 filter 視圖,它與謂詞一起使用,用于定義簡單過濾器:

    vector<int> vi { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    auto even=[](long i) { return 0==i % 2; };
    auto tview=vi | views::filter(even);


    輸出:

    0 2 4 6 8



    還包括一個 transform 視圖,它與轉換函數一起使用,用于轉換結果:

    vector<int> vi { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    auto even=[](int i) { return 0==i % 2; };
    auto x2=[](auto i) { return i * 2; };
    auto tview=vi | views::filter(even) | views::transform(x2);


    輸出:

    0 4 8 12 16


    庫中還有很多有用的視圖和視圖適配器。請查看您最喜歡的參考網站,或 (https://j.bw.org/ranges) 以獲取完整列表。

    還有更多…

    從 C++20 開始,<algorithm> 頭文件中的大多數算法都包括了用于范圍的版本。這些版本仍然在 <algorithm> 頭文件中,但在 std::ranges 名稱空間中。這使它們與舊算法區分開來。

    這意味著,你可以用一個范圍而不是兩個迭代器來調用一個算法:

    sort(v.begin(), v.end());


    你現在可以這樣調用它:

    ranges::sort(v);


    這當然更方便,但它真的有什么幫助嗎?

    考慮你想對向量的某部分進行排序的情況,你可以用舊方法這樣做:

    sort(v.begin() + 5, v.end());


    這將對向量的前 5 個元素之后的元素進行排序。使用范圍版本,你可以使用視圖跳過前 5 個元素:

    ranges::sort(views::drop(v, 5));


    你甚至可以組合視圖:

    ranges::sort(views::drop(views::reverse(v), 5));


    實際上,你可以甚至將范圍適配器作為參數傳遞給 ranges::sort:

    ranges::sort(v | views::reverse | views::drop(5));


    與使用傳統的 sort 算法和向量迭代器相比,雖然這肯定更短,也不是不可能理解,但我覺得范圍適配器的版本直觀得多。

    你可以在 cppreference 網站(https://j.bw.org/algoranges)上找到已經約束為與范圍一起工作的算法的完整列表。

    在本文中,我們只是淺嘗輒止地介紹了范圍和視圖。這個特性是十多年來許多不同團隊工作的結晶,我預計它將根本改變我們在 STL 中使用容器的方式。

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有