在C++向量中从指定索引提取元素

3

我有两个问题,非常感谢您的帮助。

我有一个矩阵 A={0 1 0 0 1 1 0 0}。现在我找到了0的索引位置并保存在向量 B={0 2 3 6 7} 中。

  1. 如何从A中提取向量B所对应的元素到一个新的向量中,而不会影响原始向量A?也就是说,我想得到C={0 0 0 0 0},这是由B索引A得到的数据。

  2. 如何删除A中由B索引的元素?

对于第二个问题,我尝试了以下代码,但没有成功。

///// erasing the elements in particular locations

sort (B.begin(), B.end());

for(int i=A.size() - 1; i >= 0; i--){

   A.erase(A.begin() + B[i]);
}

1
你的循环 #2 应该使用 B.size(),而不是 A.size()(最好使用 rbegin()rend() 迭代器)。 - WhozCraig
为什么在B的第二个循环中要使用索引呢?为什么不像现在这样向后迭代A,并且“如果(A [i] == 0){erase(A.begin()+ i); }”?这将允许您执行循环2而无需构造B向量。 - dgnuff
4个回答

2

1.如何在不破坏原始向量A的情况下,提取由向量B索引的元素?即我想获得C = {0 0 0 0 0},这是由B索引的A中的数据。

std::vector<int> C;
for (size_t i = 0; i < B.size(); ++i )
   C.push_back(A[B[i]]);

当然,我们假设 B 没有越界访问 A 向量的条目。

如果B中的元素超出了A的范围,C.push_back(A.at(B[i]))将抛出一个out_of_range异常。 - dgnuff
@dgnuff - 我在我的答案中已经包含了那个。 - PaulMcKenzie
是的,我看到了。我正在解释你可以做些什么来处理你所引用的情况。 - dgnuff

2

问题1:
如果您想创建一个新的向量,PaulMcKenxie的答案是您需要的:

std::vector<int> C;
for (size_t i = 0; i < B.size(); ++i )
   C.push_back(A[B[i]]);

Q2:
否则,您需要删除未由B索引的每个实例。 这相对复杂,因为通过以您的方式删除条目,您强制重新分配可能会使您的迭代器/指向数据的指针无效。

最好的解决方案(简单高效)是创建一个临时向量C,然后将缩小的数据交换进去。

void delete_indexes(std::vector<int> &data, std::vector<int> &indexes)
{
    std::vector<int> temp;
    for (size_t i = 0; i < indexes.size(); ++i )
    {
       temp.push_back(data[indexes[i]]);
    }
    data.swap(temp);  //does the work
}

int main()
{
    //do stuff
    delete_indexes(A,B);
}

交换选项很快(只是交换而不是删除和写入),临时向量(带有原始数据)在超出范围时被处理。
编辑:
这个答案也可能是您要寻找的,假设您有一个生成每个元素B的函数可以应用(即使它是A[i] == 1(代码已编辑以适应):
for(auto it = A.begin(); it != A.end();)
{
  if (criteria_for_B(*it))
    it = A.erase(it);
  else
    ++it;
}

0

这里有一些标准风格的通用工具(标准c++98)。

1. 在索引处提取元素

/// Extract elements from vector at indices specified by range
template <typename ForwardIt, typename IndicesForwardIt>
inline std::vector<typename std::iterator_traits<ForwardIt>::value_type>
extract_at(
    ForwardIt first,
    IndicesForwardIt indices_first,
    IndicesForwardIt indices_last)
{
    typedef std::vector<typename std::iterator_traits<ForwardIt>::value_type>
        vector_type;
    vector_type extracted;
    extracted.reserve(static_cast<typename vector_type::size_type>(
        std::distance(indices_first, indices_last)));
    for(; indices_first != indices_last; ++indices_first)
        extracted.push_back(*(first + *indices_first));
    return extracted;
}

/// Extract elements from collection specified by collection of indices
template <typename TVector, typename TIndicesVector>
inline TVector extract_at(const TVector& data, const TIndicesVector& indices)
{
    return extract_at(data.begin(), indices.begin(), indices.end());
}

2. 删除指定索引处的元素

//! Remove one element with given index from the range [first; last)
template <typename ForwardIt>
inline ForwardIt remove_at(ForwardIt first, ForwardIt last, const size_t index)
{
    std::advance(first, index);
    for(ForwardIt it = first + 1; it != last; ++it, ++first)
        *first = *it;
    return first;
}

/*!
 * Remove elements in the range [first; last) with indices from the sorted
 * range [indices_first, indices_last)
 */
template <typename ForwardIt, typename SortedIndicesForwardIt>
inline ForwardIt remove_at(
    ForwardIt first,
    ForwardIt last,
    SortedIndicesForwardIt indices_first,
    SortedIndicesForwardIt indices_last)
{
    typedef typename std::vector<bool> flags;
    // flag elements to keep
    flags is_keep(
        static_cast<flags::size_type>(std::distance(first, last)), true);
    for(; indices_first != indices_last; ++indices_first)
        is_keep[static_cast<flags::size_type>(*indices_first)] = false;
    // move kept elements to beginning
    ForwardIt result = first;
    for(flags::const_iterator it = is_keep.begin(); first != last; ++first, ++it)
        if(*it) // keep element
            *result++ = *first; //in c++11 and later use: *result++ = std::move(*first);
    return result;
}

使用方法(擦除删除成语):

std::vector<int> vec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> ii{6, 3, 1};
std::sort(ii.begin(), ii.end());
vec.erase(remove_at(vec.begin(), vec.end(), ii.begin(), ii.end()), vec.end());

0

对我来说,我使用erase函数,但是带有一个计数器来递减迭代器:

#include <iostream>
#include <vector>
using namespace std;

int main(){
  vector<int> A;
  A.push_back(0);
  A.push_back(1);
  A.push_back(0);
  A.push_back(0);
  A.push_back(1);
  A.push_back(1);
  A.push_back(0);
  A.push_back(0);

  vector<int> B;
  B.push_back(0);
  B.push_back(2);
  B.push_back(3);
  B.push_back(6);
  B.push_back(7);

  for(int i=0; i<A.size(); i++){
    cout << A[i] << "-";
  }
  cout << endl;

  vector<int> C = A;
  int ii=0;
  for(int i=0; i<B.size(); i++){
    C.erase(C.begin() -ii + B[i] );
    ii++;
  }
  for(int i=0; i<C.size(); i++){
    cout << C[i] << "-";
  }

}

你可以使用第三个向量作为我,或直接修改A。

希望这能帮到你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接