Range
C# 有 Linq,Python 有 filter 和 map 等內建函式,可以快速從一個集合中,篩選出符合特定條件的元素。 那 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;
}
執行結果
有哪些區間適配器可以使用 ?
C++20 的 <ranges> 庫引入了多種區間適配器(range adaptors),這些適配器用於修改或操作區間數據。 常見的區間適配器包括:
std::views::filter:篩選出符合條件的元素。std::views::transform:對每個元素應用轉換操作。std::views::reverse:反轉區間的順序。std::views::take:取出區間的前 n 個元素。std::views::drop:丟棄區間的前 n 個元素。std::views::take_while:取出符合條件的連續元素,直到條件不再成立。std::views::drop_while:丟棄連續的符合條件的元素,直到條件不再成立。std::views::concat:連接多個區間。std::views::zip:將多個區間中的元素組合成元組。std::views::join:將區間中的區間展平成單個區間。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;
}
執行結果
特別注意一下!! 使用範圍適配器和轉換操作,例如 std::views::transform,不會改變原始容器中的值。 這些適配器和操作都是在原始資料上產生新的「視圖」或「範圍」,而不會修改原始資料本身。
使用時機
- 數據篩選:當你需要從一個集合中篩選出符合特定條件的元素時,可以使用
std::views::filter。 - 數據轉換:當你需要對集合中的每個元素應用某種轉換(例如平方、取反、格式化等)時,可以使用
std::views::transform。 - 組合操作:你可以將多個區間適配器鏈接起來,組合出複雜的數據處理流程,而無需創建臨時容器或顯式迭代。
很方便的功能,下次可以用用看吧!


