Home Item 24 - Range (中文)
Post
Cancel

Item 24 - Range (中文)

Range

C# 有 Linq,Python 有 filtermap 等內建函式,可以快速從一個集合中,篩選出符合特定條件的元素。 那 C++ 呢 ? 只能自己 Loop 容器一遍,然後慢慢找出自己需要的部分 ? No ! C++20 header <ranges> 提供許多方便的函式,可以幫我們去完成這個情形。

code

以下示範一個簡單的例子,從一堆數字中, 找出偶數並計算平方,最後在反轉順序輸出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
int main()
{
    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    // 將數字過濾、轉換並排序
    auto result = numbers
        | std::views::filter([](int n) { return n % 2 == 0; }) // 篩選出偶數
        | std::views::transform([](int n) { return n * n; })  // 將選出來的偶數平方
        | std::views::reverse; // 反轉順序

    // 輸出結果
    for (int n : result) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

執行結果

Desktop View

有哪些區間適配器可以使用 ?

C++20 的 <ranges> 庫引入了多種區間適配器(range adaptors),這些適配器用於修改或操作區間數據。 常見的區間適配器包括:

  1. std::views::filter:篩選出符合條件的元素。
  2. std::views::transform:對每個元素應用轉換操作。
  3. std::views::reverse:反轉區間的順序。
  4. std::views::take:取出區間的前 n 個元素。
  5. std::views::drop:丟棄區間的前 n 個元素。
  6. std::views::take_while:取出符合條件的連續元素,直到條件不再成立。
  7. std::views::drop_while:丟棄連續的符合條件的元素,直到條件不再成立。
  8. std::views::concat:連接多個區間。
  9. std::views::zip:將多個區間中的元素組合成元組。
  10. std::views::join:將區間中的區間展平成單個區間。
  11. std::views::elements:提取區間中元素的某個成員或索引。
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
46
47
48
49
50
51
52
53
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

 // 定義 NBAPlayer 結構體
 struct NBAPlayer {
     std::string name;
     int number;

     // 友元函數,用於實現 << 運算符
     friend std::ostream& operator<<(std::ostream& os, const NBAPlayer& player)
     {
         os << "Name: " << player.name << ", Number: " << player.number;
         return os;
     }
 };

int main()
{
    // 創建 NBAPlayer 容器
    std::vector<NBAPlayer> players = { {"Kobe Bryant",24},{"MJ",23},{"LBJ", 23}, {"AI",3},{"AD", 0} };

    for  (auto p : players)
    {
        std::cout << p << std::endl;
    }

    // 使用區間適配器篩選出指定的球員,並將其號碼改為 24
    auto filtered_players = players
        | std::views::take(5)
        | std::views::transform([](NBAPlayer player) {player.number = 24; return  player; });

    std::cout << std::endl;
    std::cout << "---filtered_players---:" << std::endl;

    for (auto p : filtered_players)
    {
        std::cout << p << std::endl;
    }

    std::cout << std::endl;
    std::cout << "---players---:" << std::endl;

    for (auto p : players)
    {
        std::cout << p << std::endl;
    }

    return 0;
}

執行結果

Desktop View

特別注意一下!! 使用範圍適配器和轉換操作,例如 std::views::transform,不會改變原始容器中的值。 這些適配器和操作都是在原始資料上產生新的「視圖」或「範圍」,而不會修改原始資料本身。

使用時機

  1. 數據篩選:當你需要從一個集合中篩選出符合特定條件的元素時,可以使用 std::views::filter
  2. 數據轉換:當你需要對集合中的每個元素應用某種轉換(例如平方、取反、格式化等)時,可以使用 std::views::transform
  3. 組合操作:你可以將多個區間適配器鏈接起來,組合出複雜的數據處理流程,而無需創建臨時容器或顯式迭代。

很方便的功能,下次可以用用看吧!

☝ツ☝

This post is licensed under CC BY 4.0 by the author.

👈 ツ 👍

Docker 上使用 Nginx(中文)

Item 24 - Range (English)