C ++ is the best way to split a vector by n vector

I have std::vector<std::string> in this line I push_back line from a txt file, for example:

 std::string line; std::vector<std::string> path; while(getline(fichier, line)) { path.push_back(line); } 

I would like to split the vector path into n other vector out of 10 lines, for example. Therefore, if the size of my vector is 25, I want 2 other vectors of 10 elements and one vector of 5 elements.

What is the best way to do this?

+5
source share
3 answers

Best is a matter of opinion, but you can do something like the following ( bunch_size 10 ):

 for(size_t i = 0; i < strings.size(); i += bunch_size) { auto last = std::min(strings.size(), i + bunch_size); bunches.emplace_back(strings.begin() + i, strings.begin() + last); } 

demo

If your lines are large and you want to avoid copying, you can go with the move version:

 for(size_t i = 0; i < strings.size(); i += bunch_size) { auto last = std::min(strings.size(), i + bunch_size); auto index = i / bunch_size; auto& vec = bunches[index]; vec.reserve(last - i); move(strings.begin() + i, strings.begin() + last, back_inserter(vec)); } 

demo

+4
source

I suggest something pretty general (it works with different containers and different types, in this case the complexity will change):

 #include <algorithm> #include <iterator> #include <vector> template<typename Vector> auto split_vector(const Vector& v, unsigned number_lines) { using Iterator = typename Vector::const_iterator; std::vector<Vector> rtn; Iterator it = v.cbegin(); const Iterator end = v.cend(); while (it != end) { Vector v; std::back_insert_iterator<Vector> inserter(v); const auto num_to_copy = std::min(static_cast<unsigned>( std::distance(it, end)), number_lines); std::copy(it, it + num_to_copy, inserter); rtn.push_back(std::move(v)); std::advance(it, num_to_copy); } return rtn; } 

You can specify the number of lines you want to split:

For instance:

 int main(int argc, char *argv[]) { std::vector<std::string> input_vector = {"First", "Second", "Third"}; auto vs = split_vector(input_vector, 2); return 0; } 

It will generate two vectors: {"First", "Second"} and {"Third"} .

+1
source

You can use stream iterators to do the job when reading a file:

 using packet_t = Packet<5>; using filler_t = std::istream_iterator<packet_t>; std::vector<packet_t> packets{ filler_t(stream), filler_t() }; 

With a Packet structure declaring a necessary operator>> :

 template<size_t size> struct Packet { std::vector<std::string> lines; friend std::istream& operator>>(std::istream& is, Packet& packet) { packet.lines.clear(); std::string line; for(size_t i = 0; i < size && std::getline(is, line); ++i) { packet.lines.push_back(line); } if(packet.lines.size() > 0) { is.clear(); } return is; } }; 

Note that the stream is cleared when the packet is not empty for the last lines.

Full code:

 #include <iostream> #include <iterator> #include <sstream> #include <vector> template<size_t size> struct Packet { std::vector<std::string> lines; friend std::istream& operator>>(std::istream& is, Packet& packet) { packet.lines.clear(); std::string line; for(size_t i = 0; i < size && std::getline(is, line); ++i) { packet.lines.push_back(line); } if(packet.lines.size() > 0) { is.clear(); } return is; } }; int main() { std::istringstream stream("1\n2\n3\n4\n5\n6\n7\n"); using packet_t = Packet<5>; using filler_t = std::istream_iterator<packet_t>; std::vector<packet_t> packets{ filler_t(stream), filler_t() }; for(auto& packet : packets) { for(auto& line : packet.lines) { std::cout << line << " "; } std::cout << std::endl; } } 
+1
source

Source: https://habr.com/ru/post/1259909/


All Articles