如何根据另一个向量中给出的索引拆分向量?

How to split vector according to indices given in another vector?

本文关键字:向量 索引 拆分 何根 另一个      更新时间:2023-10-16

我有一个源std::vector<double>,我想根据std::vector<int>中包含的索引进行拆分。拆分是包含的,下一个切片的开始应从上一个中断的地方开始,从源矢量的开始开始。

例如:

{ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 } -> source
{2, 4, 7 } -> split indices

应用函数后,它应该产生:

{1.1, 2.2, 3.3}
{4.4, 5.5} 
{6.6, 7.7, 8.8}

我有这个不会给我第三个向量,依此类推:

vector<double> nets{ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
vector<int> ends{2, 4, 7 };
vector<vector<double>> periodnumbers;
vector<double> numbers;
for (int i = 0; i < nets.size(); i++)
{
double temp;
temp = nets[i];
numbers.push_back(temp);
for (int j = 0; j < ends.size(); j++)
{
if (i == ends[j])
{
periodnumbers.push_back(numbers);
numbers.clear();
}
}
}

算法错误

即使它有效,它也做了太多不必要的操作。从遍历所有元素开始,以push_backing结束,而不是保留/调整大小。

更好的算法

假设ends已排序。然后人们可以拿两个"滑块",并继续移动它们。左侧滑块从源矢量的开头开始,右侧滑块从第一端开始。随着算法的进展,它会复制滑块内的当前范围,将左滑块移动到右滑块,右滑块成为下一端。

#include <vector>
#include <algorithm>
std::vector<std::vector<double>> split_ends(const std::vector<double>& source, const std::vector<int>& ends) {
std::vector<std::vector<double>> result;
result.reserve(ends.size());
auto anchor_front = source.begin();
for (auto one_end: ends) {
auto anchor_end = std::next(source.begin(), one_end + 1);
result.emplace_back(anchor_front, anchor_end);
anchor_front = anchor_end;
}
return result;
}
#include <iostream>
void print(const std::vector<double>& v)
{
for (auto x: v) {
std::cout << x << ' ';
}
}
int main() {
std::vector<double> nets{1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9};
std::vector<int> ends{2, 4, 7};
auto splitted = split_ends(nets, ends);
for (const auto& v: splitted) {
print(v);
std::cout << 'n';
}
}

魔杖盒上的演示。

输出:

1.1 2.2 3.3 
4.4 5.5 
6.6 7.7 8.8 

上面的算法假设ends已排序并且不包含超出范围的索引。如果不需要副本,则可能只需保存端点迭代器,并直接对源执行更改。

if(i == ends[i])中存在错误

一种选择是使用另一个变量。

vector<double> nets{ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
vector<int> ends{2, 4, 7};
vector<vector<double>> periodnumbers;
vector<double> numbers;
int j=0;
for (int i = 0; i < nets.size(); i++)
{
double temp;
temp = nets[i];
numbers.push_back(temp);
//cout<<numbers[i]<<endl;
if (i == ends[j])
{
//cout<<i<<"  "<<nets[i]<<endl;
periodnumbers.push_back(numbers);
numbers.clear();
j++;
//break;
}
//cout<<numbers[i]<<endl;
}
cout<<"Size"<<periodnumbers.size()<<endl;
for(int i=0;i<periodnumbers.size();i++){
for(int j=0;j<periodnumbers[i].size();j++){
cout<<periodnumbers[i][j]<<" ";
}
cout<<endl; 
}
return 0;
}

有很多细节我不确定你是否考虑过。我的答案是可以调整的。

特别是,我希望WEIRD_OFFSET为 0。

#include <cassert>
#include <iostream>
#include <vector>
using std::cout;
using std::vector;

const bool ONLY = true;
const bool BEFORE_FIRST = true;
const bool AFTER_LAST = true;
const bool ALLOW_EMPTY = true;
const size_t WEIRD_OFFSET = 1;
template<class T>
vector<vector<T>> frob(const vector<T>& nets, const vector<int>& ends)
{
vector<vector<T>> rv;
if (ends.empty())
{
if (ONLY)
{
if (ALLOW_EMPTY || !nets.empty())
rv.push_back(nets);
}
}
else
{
if (BEFORE_FIRST)
{
auto bi = 0;
auto ei = ends[0] + WEIRD_OFFSET;
assert (0 <= bi && bi <= ei && ei <= nets.size());
auto b = nets.begin() + bi;
auto e = nets.begin() + ei;
if (ALLOW_EMPTY || b != e)
rv.push_back(vector<T>(b, e));
}
for (size_t i = 0; i < ends.size() - 1; ++i)
{
auto bi = ends[i] + WEIRD_OFFSET;
auto ei = ends[i+1] + WEIRD_OFFSET;
assert (0 <= bi && bi <= ei && ei <= nets.size());
auto b = nets.begin() + bi;
auto e = nets.begin() + ei;
if (ALLOW_EMPTY || b != e)
rv.push_back(vector<T>(b, e));
}
if (AFTER_LAST)
{
auto bi = ends.back() + WEIRD_OFFSET;
auto ei = nets.size();
assert (0 <= bi && bi <= ei && ei <= nets.size());
auto b = nets.begin() + bi;
auto e = nets.begin() + ei;
if (ALLOW_EMPTY || b != e)
rv.push_back(vector<T>(b, e));
}
}
return rv;
}
int main()
{
vector<double> nets{ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
vector<int> ends{2, 4, 7};
vector<vector<double>> periodnumbers = frob(nets, ends);
for (const auto& v : periodnumbers)
{
for (const auto& i : v)
{
cout << i << ' ';
}
cout << 'n';
}
cout << std::flush;
}

这会产生:

1.1 2.2 3.3 
4.4 5.5 
6.6 7.7 8.8 
9.9 

如果我们可以假设ends是按升序排序的,并且ends中的值永远不会大于nets允许的大小,那么有一个相当简单的函数可以给你想要的结果:

template<typename T>
std::vector<std::vector<T>> split(const std::vector<T>& nets, const std::vector<int>& ends)
{
std::vector<std::vector<T>> result;
int previous_offset = 0;
for (int i : ends)
{
const std::vector<T> piece(nets.begin() + previous_offset, nets.begin() + i + 1);
previous_offset = i;
result.push_back(piece);
}
return result;
}

包含示例数据的整个程序可能如下所示:

#include <iostream>
#include <vector>
// function from above
template<typename T>
std::vector<std::vector<T>> split(const std::vector<T>& nets, const std::vector<int>& ends)
{
std::vector<std::vector<T>> result;
int previous_offset = 0;
for (int i : ends)
{
const std::vector<T> piece(nets.begin() + previous_offset, nets.begin() + i + 1);
previous_offset = i;
result.push_back(piece);
}
return result;
}

int main()
{
// input data
std::vector<double> nets{ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
std::vector<int> ends{2, 4, 7 };
// variable that will hold the result
std::vector<std::vector<double>> periodnumbers;
// This is where the work happens.
periodnumbers = split(nets, ends);
// Write result to standard output.
std::cout << "There are " << static_cast<int>(periodnumbers.size()) << " pieces:" << std::endl;
for (auto vec : periodnumbers)
{
std::cout << "Next piece is: ";
for (auto elem: vec)
{
std::cout << elem << " ";
}
std::cout << std::endl;
}
return 0;
}

输出将是:

There are 3 pieces:
Next piece is: 1.1 2.2 3.3 
Next piece is: 3.3 4.4 5.5 
Next piece is: 5.5 6.6 7.7 8.8

我建议以下更简单,更容易理解的代码

#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<double> nets{ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
vector<int> ends{2, 4, 7 };
ends.push_back(nets.size()-1);
vector<vector<double>> periodnumbers;
vector<double> numbers;
int j=0;
int coming_split_index=ends[j];
for (int i = 0; i < nets.size(); i++){
if(i<=coming_split_index){
numbers.push_back(nets[i]);
}else{
j++;
coming_split_index=ends[j];
periodnumbers.push_back(numbers);
numbers.clear();
i--;
/*when the index i reaches the coming index the corresponding 
*value won't be added to any subvector because It will skip the 
*pervious instruction for this reason I decrement the counter i so 
*that it repeats it and the next time the one in the previous will 
*be executed
*/
}
}

这将显示您的结果

1.1 2.2 3.3 
4.4 5.5 
6.6 7.7 8.8