有没有一种优雅的 STL 方法来查找给定索引的数组中最接近的true
(1( 值。 例如,对于std::vector<int> v{1,1,1,0,0,0,1,1,0};
给定索引 5 的最接近的true
值位于索引 6 处。
我尝试并最终使用带有迭代器的多个 while 循环。可以使用C++STL吗?
这是我能想到的最简洁的版本。
- 使用
cbegin
从左到右>查找,从右>左查找crbegin()
。但请注意,在后一种情况下,需要进行一些计算才能获得正确的起始位置。
您将需要C++17来支持if init 语句。
#include <vector>
#include <iostream>
#include <algorithm>
#include <numeric>
int main()
{
const std::vector<int> v{ 1, 1, 1, 0, 0, 0, 1, 1, 0 };
const int index_to_find = 5;
int rdistance = std::numeric_limits<int>::max();
if (auto iter_right = std::find(std::cbegin(v) + index_to_find + 1, std::cend(v), 1); iter_right != std::cend(v))
rdistance = std::distance(std::cbegin(v) + index_to_find, iter_right);
int ldistance = std::numeric_limits<int>::max();
if (auto iter_left = std::find(std::crbegin(v) + v.size() - index_to_find, std::crend(v), 1); iter_left != std::crend(v))
ldistance = std::distance(std::crbegin(v) + v.size() - index_to_find - 1, iter_left);
if (ldistance == std::numeric_limits<int>::max() && rdistance == std::numeric_limits<int>::max())
std::cout << "Not found!n";
else
{
if (ldistance == rdistance)
std::cout << "Found at index: " << index_to_find + ldistance << " and " << index_to_find - ldistance << "n";
else
std::cout << "Found at index: " << (rdistance > ldistance ? index_to_find - ldistance : index_to_find + rdistance) << "n";
}
}
这里有一个想法,你可以扩展它来涵盖你的所有用例。
你可以使用 std::find 和 std::d istance 来实现这一点。
示例(实时(:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
int main()
{
const std::vector<int> v { 1, 1, 1, 0, 0, 0, 1, 1, 0 };
const auto it = std::find( std::begin(v) + 5, std::end(v), 1 );
if ( it == std::end(v) )
{
std::cerr << "ERROR: Not found!n";
return EXIT_FAILURE;
}
const auto index = std::distance( std::begin(v), it );
std::cout << "SUCCESS: Found at index " << index << 'n';
return EXIT_SUCCESS;
}
您可以使用默认值(即true
(,以便根据您的用例获得更好的可读性。另外,查看迭代器导航的 std::next 和 std::advance。
另一个使用基本结构的示例仅包括一些测试(实时(:
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
#include <limits>
using Result = std::tuple<bool, std::size_t, std::string>; // result (T/F), index, message
Result find_nearest( const std::vector<int>& v, const std::size_t index, const int value )
{
constexpr auto max_index = std::numeric_limits<std::size_t>::max();
if ( v.empty() || index >= v.size() )
{
return { false, max_index, "Empty container or invalid index!" };
}
std::size_t ilhs { max_index };
std::size_t irhs { max_index };
for ( std::size_t i {0}; i != v.size(); ++i )
{
if ( v[i] == value )
{
if ( i < index ) { ilhs = i; }
else if ( i > index ) { irhs = i; break; }
}
}
// if element not found i.e. no index
if ( ilhs == max_index && irhs == max_index )
{
return { false, max_index, "Index not found!" };
}
// shortest distance based comparison to determine indexes
const auto dlhs = ( ilhs != max_index ? index - ilhs : ilhs );
const auto drhs = ( irhs != max_index ? irhs - index : irhs );
if ( dlhs == drhs )
{
return { true, ilhs, "Equal distance found! Left index returned!" };
}
const auto idx = ( dlhs < drhs ? ilhs : irhs );
return { true, idx, "Index found!" };
}
int main()
{
using Args = std::tuple<std::vector<int>, std::size_t, int>; // list, index, value
using Tests = std::vector<Args>;
const Tests tests
{
{ {}, 0, 1 },
{ { 1 }, 0, 1 },
{ { 1 }, 1, 1 },
{ { 1 }, 2, 1 },
{ { 0, 0, 0 }, 1, 1 },
{ { 0, 0, 0, 1, 0 }, 2, 1 },
{ { 1, 0, 0, 0, 1 }, 2, 1 },
{ { 1, 0, 0, 1, 0, 1, 0 }, 3, 1 },
{ { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, 5, 1 },
};
for ( const auto& [list, index, value] : tests )
{
const auto& [found, idx, msg] = find_nearest( list, index, value );
if ( found )
std::cout << "INF: " << msg << " index: " << idx << 'n';
else
std::cerr << "ERR: " << msg << 'n';
}
return 0;
}
输出:
ERR: Empty container or invalid index!
ERR: Index not found!
ERR: Empty container or invalid index!
ERR: Empty container or invalid index!
ERR: Index not found!
INF: Index found! index: 3
INF: Equal distance found! Left index returned! index: 0
INF: Index found! index: 5
INF: Index found! index: 4
我相信解决这个问题的最STL和C++方法是使用std::find
,std::distance
和正向和反向迭代器的组合:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int find_closest(std::vector<int> const& v, int i) {
auto it = v.begin() + i;
auto left_truth = std::find(std::make_reverse_iterator(it), v.rend(), 1);
auto right_truth = std::find(it + 1, v.end(), 1);
auto left_distance = std::distance(std::make_reverse_iterator(it), left_truth) + 1;
auto right_distance = std::distance(it, right_truth);
auto left_truth_index = std::distance(v.begin(), --(left_truth.base()));
auto right_truth_index = std::distance(v.begin(), right_truth);
if (v.rend() != left_truth && v.end() != right_truth) {
if (left_distance < right_distance) {
return left_truth_index;
} else {
return right_truth_index;
}
} else if (v.end() == right_truth) {
return left_truth_index;
} else {
return right_truth_index;
}
}
您可能会注意到std::make_reverse_iterator
是 C++17 的一部分,但是,如果您需要使用 C++11,您可以轻松创建相同的帮助程序函数:
template <typename Iter>
constexpr std::reverse_iterator<Iter> make_reverse_iterator(Iter i) {
return std::reverse_iterator<Iter>(i);
}
现在,您可以像这样使用find_closest
函数:
int main() {
std::vector<int> v {1, 1, 1, 0, 0, 0, 1, 1, 0};
std::cout << find_closest(v, -6) << std::endl; // 0
std::cout << find_closest(v, -1) << std::endl; // 0
std::cout << find_closest(v, 0) << std::endl; // 1
std::cout << find_closest(v, 3) << std::endl; // 2
std::cout << find_closest(v, 5) << std::endl; // 6
std::cout << find_closest(v, 8) << std::endl; // 7
std::cout << find_closest(v, 10) << std::endl; // 7
return 0;
}
现场查看
这是一个非常简单的例程,您最好从头开始编写函数。只需向两个方向搜索,直到在任何一侧到达终点,然后只向一个方向搜索。
#include <vector>
#include <iterator>
#include <iostream>
template <typename IterT, typename ValueT>
IterT find_closest(IterT begin, IterT mid, IterT end, const ValueT& value)
{
if (*mid == value) return mid;
IterT lhs = mid;
IterT rhs = std::next(mid);
while(lhs != begin && rhs != end)
{
--lhs;
if (*lhs == value) return lhs;
if (*rhs == value) return rhs;
++rhs;
}
while(lhs != begin)
{
--lhs;
if (*lhs == value) return lhs;
}
while(rhs != end)
{
if (*rhs == value) return rhs;
++rhs;
}
return end;
}
int main()
{
std::vector<int> v{1,1,1,0,0,0,1,1,0};
std::cout << &(*find_closest(v.begin(), v.begin() + 0, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 1, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 2, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 3, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 4, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 5, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 6, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 7, v.end(), 1)) - &(v[0]) << 'n';
std::cout << &(*find_closest(v.begin(), v.begin() + 8, v.end(), 1)) - &(v[0]) << 'n';
}
mid
必须是可取消引用的
演示:http://coliru.stacked-crooked.com/a/66d18019fb7060f6