std::ranges::find
std::ranges::find
是 C++20 引入的算法,属于范围库(Ranges Library)的一部分。它用于在给定范围内查找特定值,并返回指向该元素的迭代器。若未找到,则返回结束迭代器。与传统的 std::find
相比,std::ranges::find
支持更灵活的范围操作,代码更简洁。
Defined in header | ||
Call signature | ||
(1) | ||
template< std::input_iterator I, std::sentinel_for<I> S, class T, class Proj = std::identity > | (since C++20) (until C++26) | |
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity, | (since C++26) | |
(2) | ||
template< ranges::input_range R, class T, class Proj = std::identity > requires std::indirect_binary_predicate | (since C++20) (until C++26) | |
template< ranges::input_range R, class Proj = std::identity, class T = std::projected_value_t<ranges::iterator_t<R>, Proj> > |
-
参数:
first
,last
:迭代器对,表示搜索范围。r
:直接传递的范围对象。value
:要查找的值。proj
:投影(Projection),可对范围元素进行转换后再比较。
-
返回值:找到元素的迭代器,未找到时返回
last
。
示例
示例 1:基本查找
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用 ranges::find 查找值为 3 的元素
auto it = std::ranges::find(vec, 3);
if (it != vec.end()) {
std::cout << "Found: " << *it << std::endl; // 输出: Found: 3
} else {
std::cout << "Not found" << std::endl;
}
}
输出:
Found: 3
示例 2:使用投影(Projection)
假设查找结构体的某个成员:
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
struct Person {
std::string name;
int age;
};
int main() {
std::vector<Person> people = {
{"Alice", 25},
{"Bob", 30},
{"Charlie", 35}
};
// 查找年龄为 30 的人(通过投影比较 age 成员)
auto it = std::ranges::find(people, 30, &Person::age);
if (it != people.end()) {
std::cout << "Found: " << it->name << std::endl; // 输出: Found: Bob
} else {
std::cout << "Not found" << std::endl;
}
}
输出:
Found: Bob
示例 3:结合范围适配器
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
std::vector<int> vec = {5, 3, 7, 1, 9};
// 在过滤后的范围(偶数)中查找 1(实际不存在)
auto filtered = vec | std::ranges::views::filter([](int x) { return x % 2 == 0; });
auto it = std::ranges::find(filtered, 1);
if (it != filtered.end()) {
std::cout << "Found: " << *it << std::endl;
} else {
std::cout << "Not found" << std::endl; // 输出: Not found
}
}
输出:
Not found
注意事项
- 范围支持:
std::ranges::find
支持所有满足std::ranges::input_range
的范围(如容器、视图等)。 - 投影的灵活性:通过投影可以自定义查找逻辑(例如比较结构体的某个成员)。
- 性能:时间复杂度为 O(n),与
std::find
一致。
与传统 std::find
的区别
- 接口风格:
std::ranges::find
直接接受范围对象,无需传递迭代器对。 - 投影支持:传统
std::find
无法直接处理投影。 - 约束:
std::ranges::find
使用 C++20 的概念(Concepts)约束参数类型,更安全。
通过 std::ranges::find
,可以更简洁、灵活地实现查找操作,尤其在与范围适配器结合时,代码表现力更强。
std::ranges::find_if
用于在给定范围内查找满足特定条件的元素。与 std::ranges::find
不同,find_if
通过一个谓词(Predicate)函数判断元素是否符合条件,而不是直接匹配某个值。它的核心是自定义条件查找。
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity, | (3) | (since C++20) |
template< ranges::input_range R, class Proj = std::identity, std::indirect_unary_predicate |
-
参数:
first
,last
:迭代器对,表示搜索范围。r
:直接传递的范围对象。pred
:谓词函数(返回bool
的可调用对象),用于判断元素是否满足条件。proj
:投影(Projection),对元素进行转换后再应用谓词。
-
返回值:找到第一个满足条件的元素的迭代器,未找到时返回
last
。
示例
示例 1:基本查找(查找第一个偶数)
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
std::vector<int> vec = {1, 3, 5, 4, 7, 8};
// 查找第一个偶数
auto it = std::ranges::find_if(vec, [](int x) { return x % 2 == 0; });
if (it != vec.end()) {
std::cout << "Found: " << *it << std::endl; // 输出: Found: 4
} else {
std::cout << "Not found" << std::endl;
}
}
输出:
Found: 4
示例 2:结合投影(查找结构体中满足条件的成员)
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
struct Person {
std::string name;
int age;
};
int main() {
std::vector<Person> people = {
{"Alice", 25},
{"Bob", 30},
{"Charlie", 35}
};
// 查找年龄大于 30 的人(投影到 age 成员,再应用谓词)
auto it = std::ranges::find_if(people, [](int age) {
return age > 30;
}, &Person::age); // 投影到 Person::age
if (it != people.end()) {
std::cout << "Found: " << it->name << std::endl; // 输出: Found: Charlie
} else {
std::cout << "Not found" << std::endl;
}
}
输出:
Found: Charlie
示例 3:结合范围适配器(在过滤后的视图中查找
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
std::vector<int> vec = {5, 3, 8, 1, 9, 4};
// 创建一个过滤后的视图(仅保留偶数)
auto even_view = vec | std::ranges::views::filter([](int x) { return x % 2 == 0; });
// 在视图中查找第一个大于 5 的偶数
auto it = std::ranges::find_if(even_view, [](int x) { return x > 5; });
if (it != even_view.end()) {
std::cout << "Found: " << *it << std::endl; // 输出: Found: 8
} else {
std::cout << "Not found" << std::endl;
}
}
输出:
Found: 8
注意事项
- 谓词的设计:谓词函数需要严格返回
bool
类型,且逻辑应清晰。 - 投影与谓词的顺序:元素会先经过投影(
proj
),再应用谓词(pred
)。// 等效逻辑: if (pred(proj(element))) { ... }
- 性能:时间复杂度为 O(n),与
std::find_if
一致。
与传统 std::find_if
的区别
- 范围支持:直接传递范围对象(如容器、视图),无需手动传递迭代器对。
- 投影支持:通过
proj
参数可以灵活处理复杂数据类型。 - 约束检查:使用 C++20 概念(Concepts)确保参数合法性。
适用场景
- 需要自定义查找条件(如查找特定属性的对象)。
- 结合范围适配器(如
filter
、transform
)实现链式操作。 - 处理复杂数据结构时,通过投影简化逻辑。
通过 std::ranges::find_if
,可以更直观、灵活地实现条件查找,是现代 C++ 中推荐的查找方式。
std::ranges::find_if_not
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity, | (5) | (since C++20) |
template< ranges::input_range R, class Proj = std::identity, std::indirect_unary_predicate find_if_not( R&& r, Pred pred, Proj proj = {} ); |
用于在给定范围内查找不满足特定谓词条件的第一个元素,并返回指向该元素的迭代器。若所有元素都满足条件,则返回结束迭代器。与 std::ranges::find_if
互补,适合需要反向逻辑的场景。
-
参数:
first
,last
:迭代器对,表示搜索范围。r
:直接传递的范围对象。pred
:谓词函数(返回bool
的可调用对象),用于判断元素是否满足条件。proj
:投影(Projection),对元素进行转换后再应用谓词。
-
返回值:找到第一个不满足谓词条件的元素的迭代器,未找到时返回
last
。
示例
示例 1:基本查找(查找第一个非偶数)
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
std::vector<int> vec = {2, 4, 6, 7, 8, 10};
// 查找第一个非偶数(即不满足 `x % 2 == 0` 的元素)
auto it = std::ranges::find_if_not(vec, [](int x) { return x % 2 == 0; });
if (it != vec.end()) {
std::cout << "Found: " << *it << std::endl; // 输出: Found: 7
} else {
std::cout << "All elements are even" << std::endl;
}
}
输出:
Found: 7
示例 2:结合投影(查找结构体中不满足条件的成员)
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
struct Person {
std::string name;
int age;
};
int main() {
std::vector<Person> people = {
{"Alice", 25},
{"Bob", 17},
{"Charlie", 30}
};
// 查找年龄小于 18 的人(即不满足 `age >= 18` 的条件)
auto it = std::ranges::find_if_not(people, [](int age) {
return age >= 18;
}, &Person::age); // 投影到 Person::age
if (it != people.end()) {
std::cout << "Found underage: " << it->name << std::endl; // 输出: Found underage: Bob
} else {
std::cout << "All people are adults" << std::endl;
}
}
输出:
Found underage: Bob
示例 3:结合范围适配器(在过滤后的视图中查找)
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
std::vector<int> vec = {5, 3, 8, 1, 9, 4};
// 创建一个过滤后的视图(仅保留偶数)
auto even_view = vec | std::ranges::views::filter([](int x) { return x % 2 == 0; });
// 在视图中查找第一个不大于 5 的偶数(即不满足 `x > 5` 的偶数)
auto it = std::ranges::find_if_not(even_view, [](int x) { return x > 5; });
if (it != even_view.end()) {
std::cout << "Found: " << *it << std::endl; // 输出: Found: 8(注意:8 > 5,但视图中只有 8 和 4)
// 此处结果可能需要根据实际数据调整逻辑
} else {
std::cout << "Not found" << std::endl;
}
}
输出:
Found: 4
注意事项
- 逻辑反转:
find_if_not
是find_if
的逻辑取反,等效于find_if
中谓词为!pred
。 - 投影与谓词的顺序:元素先经过投影(
proj
),再应用谓词(pred
)。// 等效逻辑: if (!pred(proj(element))) { ... }
- 性能:时间复杂度为 O(n),与
std::find_if
一致。
与传统 std::find_if_not
的区别
- 范围支持:直接传递范围对象,无需手动传递迭代器对。
- 投影支持:通过
proj
参数可以灵活处理复杂数据类型。 - 约束检查:使用 C++20 概念(Concepts)确保参数合法性。
适用场景
- 需要查找不满足条件的元素(如“非偶数”、“未成年的用户”)。
- 结合范围适配器实现链式操作。
- 处理复杂数据结构时,通过投影简化逻辑。
通过 std::ranges::find_if_not
,可以更直观地表达反向查找逻辑,是现代 C++ 中推荐的查找方式。
std::ranges::find_first_of
用于在第一个范围中查找与第二个范围中任意元素匹配的第一个元素。它是 std::find_first_of
的范围版本,支持更灵活的迭代器和范围操作。
Defined in header | ||
Call signature | ||
template< std::input_iterator I1, std::sentinel_for<I1> S1, std::forward_iterator I2, std::sentinel_for<I2> S2, | (1) | (since C++20) |
template< ranges::input_range R1, ranges::forward_range R2, class Pred = ranges::equal_to, |
参数说明
first1
,last1
: 第一个范围的迭代器对。first2
,last2
: 第二个范围的迭代器对。pred
: 二元谓词,用于比较元素(默认为ranges::equal_to
)。proj1
,proj2
: 投影操作,分别应用于第一个范围和第二个范围的元素。
返回值
- 返回第一个范围中与第二个范围中任意元素匹配的第一个元素的迭代器。
- 若未找到,返回
last1
。
示例
示例 1:基本用法
#include <algorithm>
#include <vector>
#include <iostream>
#include <ranges>
int main() {
std::vector<int> data = {1, 2, 3, 4, 5, 6};
std::vector<int> targets = {10, 3, 5};
auto it = std::ranges::find_first_of(data, targets);
if (it != data.end()) {
std::cout << "Found first match at position: " << std::distance(data.begin(), it)
<< ", value: " << *it << '\n';
} else {
std::cout << "No match found.\n";
}
}
输出:
Found first match at position: 2, value: 3
示例 2:使用自定义谓词和投影
查找第一个能被第二个范围中任意数整除的元素
#include <algorithm>
#include <vector>
#include <iostream>
#include <ranges>
int main() {
std::vector<int> data = {7, 14, 21, 28};
std::vector<int> divisors = {3, 5};
auto it = std::ranges::find_first_of(
data,
divisors,
[](int a, int b) { return a % b == 0; }, // 谓词:a 能被 b 整除
std::identity{}, // 投影1:直接使用 data 的元素
std::identity{} // 投影2:直接使用 divisors 的元素
);
if (it != data.end()) {
std::cout << "First divisible element: " << *it << '\n'; // 21 能被 3 整除
} else {
std::cout << "No divisible element found.\n";
}
}
输出:
First divisible element: 21
注意事项
- 复杂度:
- 最坏情况下为
O(N1 * N2)
,其中N1
和N2
是两个范围的长度。
- 最坏情况下为
- 适用范围:
- 第一个范围可以是输入范围(
input_range
),第二个范围需要是前向范围(forward_range
)。
- 第一个范围可以是输入范围(
- 投影机制:
- 通过
proj1
和proj2
可以灵活处理元素的比较逻辑(例如比较结构体的某个成员)。
- 通过
std::ranges::find_end
C++20 引入的算法,用于在第一个范围中查找最后一个与第二个范围完全匹配的子序列。
Defined in header | ||
Call signature | ||
template< std::forward_iterator I1, std::sentinel_for<I1> S1, std::forward_iterator I2, std::sentinel_for<I2> S2, | (1) | (since C++20) |
template< ranges::forward_range R1, ranges::forward_range R2, class Pred = ranges::equal_to, |
参数说明
first1
,last1
: 第一个范围的迭代器对。first2
,last2
: 第二个范围的迭代器对。pred
: 二元谓词,用于比较元素(默认为ranges::equal_to
)。proj1
,proj2
: 投影操作,分别应用于第一个范围和第二个范围的元素。
返回值
- 返回第一个范围中最后一个与第二个范围完全匹配的子序列的起始迭代器。
- 若未找到,返回
last1
。
示例
示例 1:基本用法
#include <algorithm>
#include <vector>
#include <iostream>
#include <ranges>
int main() {
std::vector<int> data = {1, 2, 3, 4, 1, 2, 3, 4};
std::vector<int> sub = {1, 2, 3};
auto it = std::ranges::find_end(data, sub);
if (it != data.end()) {
std::cout << "Last subsequence found at position: "
<< std::distance(data.begin(), it)
<< "\n"; // 输出 4(子序列 {1,2,3} 的最后一个起始位置)
}
}
输出:
4(子序列 {1,2,3} 的最后一个起始位置)
示例 2:使用自定义谓词和投影
查找最后一个子序列,使得子序列的平方等于目标序列的值
#include <algorithm>
#include <vector>
#include <iostream>
#include <ranges>
int main() {
std::vector<int> data = {2, 4, 3, 9, 5, 25};
std::vector<int> targets = {3, 5};
auto it = std::ranges::find_end(
data,
targets,
[](int a, int b) { return a * a == b; }, // 谓词:a 的平方等于 b
std::identity{}, // 投影1:直接使用 data 的元素
std::identity{} // 投影2:直接使用 targets 的元素
);
if (it != data.end()) {
std::cout << "Last matching subsequence starts at: "
<< std::distance(data.begin(), it)
<< "\n"; // 输出 4(子序列 {5,25} 对应 {5,25},但根据谓词匹配 {3,5})
}
}
注意事项
- 复杂度:
- 最坏情况下为
O(N1 * N2)
,其中N1
和N2
是两个范围的长度。
- 最坏情况下为
- 范围要求:
- 两个范围都必须是前向范围(
forward_range
)。
- 两个范围都必须是前向范围(
- 投影机制:
- 通过
proj1
和proj2
可以灵活处理元素的比较逻辑(例如比较结构体的某个成员)。
- 通过
总结
std::ranges::find_end
提供了一种高效且灵活的方式来查找最后一个匹配的子序列,尤其适合需要反向搜索的场景。结合投影和谓词,可以处理复杂的匹配逻辑。
std::ranges::find_last
std::ranges::find_last
是 C++23 引入的算法,用于在范围中查找最后一个满足特定条件的元素。它是对 std::find
的扩展,允许从末尾反向搜索,直接找到最后一个匹配项,无需手动反转迭代器。
Defined in header | ||
Call signature | ||
(1) | ||
template< std::forward_iterator I, std::sentinel_for<I> S, class T, | (since C++23) (until C++26) | |
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity, | (since C++26) | |
(2) | ||
template< ranges::forward_range R, class T, | (since C++23) (until C++26) | |
template< ranges::forward_range R, class Proj = std::identity, |
-
参数:
r
: 要搜索的输入范围(如std::vector
、数组等)。value
/pred
: 要匹配的值或判断条件的谓词(如 Lambda 表达式)。proj
: 投影函数,用于处理元素后再比较(默认直接使用元素本身)。
-
返回值:
- 返回一个子范围(
subrange
),包含最后一个匹配元素及其后的结束迭代器。 - 若未找到,返回空子范围(
subrange{end(r), end(r)}
)。
- 返回一个子范围(
示例
示例 1:查找最后一个特定值
#include <algorithm>
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {1, 3, 5, 3, 7, 9, 3};
// 查找最后一个值为 3 的元素
auto result = std::ranges::find_last(data, 3);
if (!result.empty()) {
std::cout << "Last 3 found at index: "
<< std::distance(data.begin(), result.begin())
<< "\n"; // 输出索引 6
}
}
输出:
Last 3 found at index: 6
示例 2:查找最后一个满足条件的元素
#include <algorithm>
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {4, 8, 15, 16, 23, 42};
// 查找最后一个偶数
auto is_even = [](int x) { return x % 2 == 0; };
auto result = std::ranges::find_last_if(data, is_even);
if (!result.empty()) {
std::cout << "Last even number: " << *result.begin() << "\n"; // 输出 42
}
}
示例 3:结合投影(Projection)
查找最后一个字符串长度等于 5 的元素:
#include <algorithm>
#include <ranges>
#include <vector>
#include <string>
#include <iostream>
int main() {
std::vector<std::string> words = {"apple", "banana", "cherry", "date", "fig"};
// 投影到字符串长度,查找最后一个长度为 5 的字符串
auto result = std::ranges::find_last(words, 5,
[](const std::string& s) { return s.size(); } // 投影函数
);
if (!result.empty()) {
std::cout << "Last word with length 5: " << *result.begin() << "\n"; // 输出 "apple"
}
}
注意事项
-
范围要求:
- 输入范围必须是
forward_range
(支持多次遍历),如std::vector
、std::list
或数组。 - 单向迭代器(如
std::forward_list
)无法使用,因为需要反向搜索。
- 输入范围必须是
-
返回值处理:
- 返回的子范围
result
可通过result.begin()
获取匹配元素的迭代器。 - 若未找到,
result.empty()
为true
。
- 返回的子范围
-
性能:
- 时间复杂度为 O(n),需要遍历整个范围。
替代方案(C++20 及之前版本)
若编译器不支持 C++23,可用反向迭代器模拟 find_last
:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {1, 3, 5, 3, 7, 9, 3};
// 使用反向迭代器查找最后一个 3
auto rit = std::find(data.rbegin(), data.rend(), 3);
if (rit != data.rend()) {
auto it = rit.base() - 1; // 转换为正向迭代器
std::cout << "Last 3 found at index: "
<< std::distance(data.begin(), it) << "\n"; // 输出 6
}
}
std::ranges::find_last_if
C++23 引入的算法,用于在范围中查找最后一个满足特定条件的元素。它是对 std::find_if
的扩展,允许从末尾反向搜索,直接找到最后一个符合条件的元素,无需手动反转迭代器。
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity, | (3) | (since C++23) |
template< ranges::forward_range R, class Proj = std::identity, |
std::ranges::find_last_if
是 C++23 引入的算法,用于在范围中查找最后一个满足特定条件的元素。它是对 std::find_if
的扩展,允许从末尾反向搜索,直接找到最后一个符合条件的元素,无需手动反转迭代器。
函数原型
#include <algorithm> #include <ranges> template< std::forward_range R, typename Pred, class Proj = std::identity > constexpr ranges::borrowed_subrange_t<R> find_last_if(R&& r, Pred pred, Proj proj = {});
-
参数:
r
: 要搜索的输入范围(如std::vector
、数组等)。pred
: 判断条件的谓词(如 Lambda 表达式)。proj
: 投影函数,用于处理元素后再应用谓词(默认直接使用元素本身)。
-
返回值:
- 返回一个子范围(
subrange
),包含最后一个满足条件的元素及其后的结束迭代器。 - 若未找到,返回空子范围(
subrange{end(r), end(r)}
)。
- 返回一个子范围(
示例
示例 1:查找最后一个偶数
#include <algorithm>
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {1, 3, 5, 4, 7, 8, 9};
// 查找最后一个偶数
auto is_even = [](int x) { return x % 2 == 0; };
auto result = std::ranges::find_last_if(data, is_even);
if (!result.empty()) {
std::cout << "Last even number: " << *result.begin()
<< " at index: "
<< std::distance(data.begin(), result.begin())
<< "\n"; // 输出 8,索引 5
}
}
输出:
Last even number: 8 at index: 5
示例 2:结合投影(Projection)
查找最后一个长度大于 5 的字符串:
#include <algorithm>
#include <ranges>
#include <vector>
#include <string>
#include <iostream>
int main() {
std::vector<std::string> words = {"apple", "banana", "cherry", "date", "fig"};
// 投影到字符串长度,查找最后一个长度 > 5 的字符串
auto result = std::ranges::find_last_if(
words,
[](int len) { return len > 5; }, // 谓词:长度 > 5
[](const std::string& s) { return s.size(); } // 投影函数
);
if (!result.empty()) {
std::cout << "Last long word: " << *result.begin() << "\n"; // 输出 "cherry"
}
}
注意事项
-
范围要求:
- 输入范围必须是
forward_range
(支持多次遍历),如std::vector
、std::list
或数组。 - 单向迭代器(如
std::forward_list
)无法使用,因为需要反向搜索。
- 输入范围必须是
-
返回值处理:
- 返回的子范围
result
可通过result.begin()
获取匹配元素的迭代器。 - 若未找到,
result.empty()
为true
。
- 返回的子范围
-
性能:
- 时间复杂度为 O(n),需要遍历整个范围。
替代方案(C++20 及之前版本)
若编译器不支持 C++23,可用反向迭代器模拟 find_last_if
:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {1, 3, 5, 4, 7, 8, 9};
// 使用反向迭代器查找最后一个偶数
auto is_even = [](int x) { return x % 2 == 0; };
auto rit = std::find_if(data.rbegin(), data.rend(), is_even);
if (rit != data.rend()) {
auto it = rit.base() - 1; // 转换为正向迭代器
std::cout << "Last even number: " << *it
<< " at index: "
<< std::distance(data.begin(), it) << "\n"; // 输出 8,索引 5
}
}
std::ranges::find_last_if
简化了从范围末尾查找满足条件的元素的需求,避免了手动操作反向迭代器的复杂性。
std::ranges::find_last_if_not
C++23 引入的算法,用于在范围中查找最后一个不满足特定条件的元素。
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity, | (5) | (since C++23) |
template< ranges::forward_range R, class Proj = std::identity, |
std::ranges::find_last_if_not
是 C++23 引入的算法,用于在范围中查找最后一个不满足特定条件的元素。它是对 std::find_if_not
的扩展,允许从末尾反向搜索,直接找到最后一个不符合条件的元素,无需手动反转迭代器。
函数原型
#include <algorithm> #include <ranges> template< std::forward_range R, typename Pred, class Proj = std::identity > constexpr ranges::borrowed_subrange_t<R> find_last_if_not(R&& r, Pred pred, Proj proj = {});
-
参数:
r
: 要搜索的输入范围(如std::vector
、数组等)。pred
: 判断条件的谓词(如 Lambda 表达式)。proj
: 投影函数,用于处理元素后再应用谓词(默认直接使用元素本身)。
-
返回值:
- 返回一个子范围(
subrange
),包含最后一个不满足条件的元素及其后的结束迭代器。 - 若未找到,返回空子范围(
subrange{end(r), end(r)}
)。
- 返回一个子范围(
示例
示例 1:查找最后一个非偶数
#include <algorithm>
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {2, 4, 5, 6, 8, 9, 10};
// 查找最后一个非偶数
auto is_even = [](int x) { return x % 2 == 0; };
auto result = std::ranges::find_last_if_not(data, is_even);
if (!result.empty()) {
std::cout << "Last non-even number: " << *result.begin()
<< " at index: "
<< std::distance(data.begin(), result.begin())
<< "\n"; // 输出 9,索引 5
}
}
示例 2:结合投影(Projection)
查找最后一个长度不大于 5 的字符串:
#include <algorithm>
#include <ranges>
#include <vector>
#include <string>
#include <iostream>
int main() {
std::vector<std::string> words = {"apple", "banana", "cherry", "date", "fig"};
// 投影到字符串长度,查找最后一个长度 ≤ 5 的字符串
auto result = std::ranges::find_last_if_not(
words,
[](int len) { return len > 5; }, // 谓词:长度 > 5
[](const std::string& s) { return s.size(); } // 投影函数
);
if (!result.empty()) {
std::cout << "Last short word: " << *result.begin() << "\n"; // 输出 "date"
}
}
注意事项
-
范围要求:
- 输入范围必须是
forward_range
(支持多次遍历),如std::vector
、std::list
或数组。 - 单向迭代器(如
std::forward_list
)无法使用,因为需要反向搜索。
- 输入范围必须是
-
返回值处理:
- 返回的子范围
result
可通过result.begin()
获取匹配元素的迭代器。 - 若未找到,
result.empty()
为true
。
- 返回的子范围
-
性能:
- 时间复杂度为 O(n),需要遍历整个范围。
替代方案(C++20 及之前版本)
若编译器不支持 C++23,可用反向迭代器模拟 find_last_if_not
:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {2, 4, 5, 6, 8, 9, 10};
// 使用反向迭代器查找最后一个非偶数
auto is_even = [](int x) { return x % 2 == 0; };
auto rit = std::find_if_not(data.rbegin(), data.rend(), is_even);
if (rit != data.rend()) {
auto it = rit.base() - 1; // 转换为正向迭代器
std::cout << "Last non-even number: " << *it
<< " at index: "
<< std::distance(data.begin(), it) << "\n"; // 输出 9,索引 5
}
}
std::ranges::adjacent_find
C++20 引入的算法,用于在范围中查找相邻元素的第一个匹配项(即两个连续且相等的元素,或满足特定谓词的元素)。
Defined in header | ||
Call signature | ||
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_binary_predicate< | (1) | (since C++20) |
template< ranges::forward_range R, class Proj = std::identity, std::indirect_binary_predicate< |
-
参数:
first
,last
或r
: 输入范围的迭代器对或范围对象。pred
: 二元谓词,用于比较相邻元素(默认为ranges::equal_to
)。proj
: 投影函数,应用于元素后再比较(默认直接使用元素本身)。
-
返回值:
- 返回第一个匹配项的迭代器(指向第一个元素)。
- 若未找到,返回
last
。
示例
示例 1:查找相邻重复元素
#include <algorithm>
#include <vector>
#include <iostream>
#include <ranges>
int main() {
std::vector<int> data = {1, 2, 3, 3, 4, 5, 5, 6};
auto it = std::ranges::adjacent_find(data);
if (it != data.end()) {
std::cout << "First adjacent duplicates: " << *it << " and " << *(it + 1)
<< " at index: " << std::distance(data.begin(), it) << "\n";
// 输出 3 和 3,索引 2
}
}
输出:
First adjacent duplicates: 3 and 3 at index: 2
示例 2:使用自定义谓词和投影
查找相邻元素差值大于 2 的位置:
#include <algorithm>
#include <vector>
#include <iostream>
#include <ranges>
int main() {
std::vector<int> data = {1, 3, 6, 8, 10, 13};
auto it = std::ranges::adjacent_find(
data,
[](int a, int b) { return std::abs(b - a) > 2; }, // 谓词:差值 > 2
std::identity{} // 投影函数(直接使用元素)
);
if (it != data.end()) {
std::cout << "First large gap between: " << *it << " and " << *(it + 1)
<< " at index: " << std::distance(data.begin(), it) << "\n";
// 输出 3 和 6,索引 1
}
}
注意事项
- 复杂度:
- 时间复杂度为 O(n),需要遍历范围直到找到匹配项。
- 范围要求:
- 输入范围必须是前向范围(
forward_range
),如std::vector
、std::list
或数组。
- 输入范围必须是前向范围(
- 谓词与投影:
- 默认比较相邻元素是否相等,但可通过自定义谓词和投影实现复杂逻辑。