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

时间:2018-06-28 20:30:32

标签: c++ vector split

我有一个来源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();
        }
    }
}

5 个答案:

答案 0 :(得分:1)

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;
}

答案 1 :(得分:1)

错误算法

即使成功,它也会执行过多不必要的操作。从循环所有元素开始,以push_back结束,而不是保留/调整大小。

更好的算法

让我们假设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';
    }
}

Demo on Wandbox

输出:

1.1 2.2 3.3 
4.4 5.5 
6.6 7.7 8.8 

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

答案 2 :(得分:0)

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

尤其是,我希望cores <- c("Average", "Core1", "Core2", "Core5") Free <- c(65, 60, 80,50) Used <- c(100-65, 40, 20,50) data <- data.frame(cores, Free, Used) plot_ly(data, x = ~cores, y = ~Used, type = 'bar', name = 'Used') %>% add_trace(y = ~Free, name = 'Free') %>% layout(yaxis = list(title = '%'), barmode = 'stack') 为0。

WEIRD_OFFSET

这将产生:

#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;
}

答案 3 :(得分:0)

如果我们可以假设df.index 是按升序排序的,并且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;
}

答案 4 :(得分:0)

我提出了以下代码,它们更简单易懂

#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