查找索引的最接近的真实值

Finding the closest true value for an index

本文关键字:真实 最接近 查找 索引      更新时间:2023-10-16

有没有一种优雅的 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::findstd::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