How to split a vector into n “almost equal” parts

后端 未结 7 616
野性不改
野性不改 2020-12-18 20:03

I have a problem that I would like to merge a large number of images using ImageMagick\'s convert.exe, but under Windows I have a 8192 byte long command line limit.

相关标签:
7条回答
  • 2020-12-18 20:35

    You don't have to create new sub-vectors, use something like following:

    size_t ProcessSubVec(const vector<Image>& images, size_t begin, size_t end)
    {
        // your processing logic
    }
    
    void SplitVec(const vector<Image>& images, int cnt)
    {
        size_t SubVecLen = images.size() / cnt,
               LeftOvers = images.size() % cnt,
               i = 0;
    
        // Split into "cnt" partitions
        while(i < images.size())
            i += ProcessSubVec(images, i, i + SubVecLen + (LeftOvers-- == 0 ? 0 : 1));
    }
    

    Hope this helps.

    0 讨论(0)
  • 2020-12-18 20:41

    CreateProcess has a 32kb limit

    Or, if you want to go via the shell,

    vec::const_iterator i = vec .begin ();
    vec::const_iterator j = i + stride;
    
    while (j < vec .end ()) {
        do_range (i, j);
        i = j;
        j += stride;
    }
    
    do_range (i, vec .end ());
    
    0 讨论(0)
  • 2020-12-18 20:44

    Here is my solution:

    template<typename T>
    std::vector<std::vector<T>> SplitVector(const std::vector<T>& vec, size_t n)
    {
        std::vector<std::vector<T>> outVec;
    
        size_t length = vec.size() / n;
        size_t remain = vec.size() % n;
    
        size_t begin = 0;
        size_t end = 0;
    
        for (size_t i = 0; i < std::min(n, vec.size()); ++i)
        {
            end += (remain > 0) ? (length + !!(remain--)) : length;
    
            outVec.push_back(std::vector<T>(vec.begin() + begin, vec.begin() + end));
    
            begin = end;
        }
    
        return outVec;
    }
    
    0 讨论(0)
  • 2020-12-18 20:49

    You could create a template that returns a std::vector < std::vector > and receives the vector you want split, and the number of divisions. using for and iterator is very easy.

    #include <iostream>
    #include <iomanip>
    #include <vector>
    #include <algorithm>
    #include <numeric>
    
    template<typename T>
    std::vector< std::vector<T> > split(std::vector<T> vec, uint64_t n) {
      std::vector< std::vector<T> > vec_of_vecs(n);
    
      uint64_t quotient = vec.size() / n;
      uint64_t reminder = vec.size() % n;
      uint64_t first = 0;
      uint64_t last;
      for (uint64_t i = 0; i < n; ++i) {
        if (i < reminder) {
          last = first + quotient + 1;
          vec_of_vecs[i] = std::vector<T>(vec.begin() + first, vec.begin() + last);
          first = last;
      }
        else if (i != n - 1) {
        last = first +  quotient;
        vec_of_vecs[i] = std::vector<T>(vec.begin() + first, vec.begin() + last);
        first = last;
      }
        else
        vec_of_vecs[i] = std::vector<T>(vec.begin() + first, vec.end());
    }
    
    return vec_of_vecs;
    }
    
    #define ONE_DIMENSION 11
    #define SPLITS 3
    
    int main(void)
    {
      std::vector<uint64_t> vector(ONE_DIMENSION);
      std::iota(std::begin(vector), std::end(vector), 1);
    
      std::vector<std::vector<uint64_t>> vecs(SPLITS);
      vecs = split(vector, SPLITS);
    
      for (uint64_t m = 0; m < vecs.size(); ++m) {
        for (auto i : vecs[m])
          std::cout << std::setw(3) << i << " ";
        std::cout << std::endl;
      }
    
    
      return 0;
    }
    
    0 讨论(0)
  • 2020-12-18 20:51

    To get a base number for the size of each part, simply divide the total by the number of parts: 11/3 = 3. Obviously some of the parts will need to be bigger than that to get the proper total, but that's just the remainder: 11 % 3 = 2. So now you know that 2 of the parts will be size 3+1, and whatever's left over will be 3.

    0 讨论(0)
  • You can use iterators to iterate through the sub-parts of the problem. Iterators usage is similar to pointers to elements of the vector

    What you want to on the images do could be implemented as a function

    using namespace std; 
    void do_some_work(vector<image>::iterator begin, vector<image>::iterator end) {
        vector<image>::iterator i = begin ;
        while(i != end) {
            // do something using *i , which will be of type image
            ++i ;
        }
    }
    
    0 讨论(0)
提交回复
热议问题