2011-07-28 20 views
13

Mam problem, że chciałbym scalić dużą liczbę obrazów przy użyciu programu convert.exe ImageMagick, ale w systemie Windows mam limit wiersza poleceń wynoszący 8192 bajtów.Jak podzielić wektor na n "prawie równe" części

Moim rozwiązaniem jest podzielenie zadania na mniejsze pod-zadanie, uruchomienie i wykonanie końcowego zadania, które je łączy.

Mój pomysł polega na napisaniu funkcji, która pobiera wektor obrazów i liczbę całkowitą, i dzieli wektor na n pod-wektor, wszystkie mające "prawie równe" części.

Na przykład, jeśli chciałbym podzielić 11 na 3 grupy, byłoby to 4-4-3.

Czy możesz mi powiedzieć, jak mogę to zrobić w C++? Mam na myśli, aby napisać funkcję

który dzieli?

Czy możesz mi powiedzieć, jaki jest najskuteczniejszy sposób na wykonanie , jeśli nie potrzebuję tworzyć nowych wektorów, po prostu przejrzyj pod-części? Podobnie jak funkcja std::substr z std::string?

Uwaga: Korzystam już z Boost w projekcie, więc jeśli jest w nim trochę fajnego narzędzia, to jest to dla mnie idealne.

Odpowiedz

10

Aby uzyskać numer bazowy dla wielkości każdej części, po prostu podziel sumę przez liczbę części: 11/3 = 3. Oczywiście niektóre części muszą być większe, aby uzyskać odpowiednią sumę , ale to tylko pozostała: 11% 3 = 2. Więc teraz wiesz, że 2 z tych części będzie wielkość 3 + 1, a co pozostało ponad będą 3.

+0

Dzięki, oto co wymyślę: podwójna pętla = liczba/części; for (int i = 0; i zsero

+0

@zsero, jeśli zarówno 'liczba' jak i' części' są liczbami całkowitymi, musisz przekonwertować jeden do podwójnego przed wykonaniem podziału. Ponadto musisz się martwić o błąd zaokrąglania, istnieją przypadki, w których możesz uzyskać błąd "jeden po drugim", gdy konwertujesz z powrotem na liczbę całkowitą. –

+0

Właściwie używam podwójnych w definicji funkcji i funkcji round() dla początku i końca. Czy sądzisz, że przy użyciu funkcji round() można mieć błąd roundoff? (Używam stringstream do rundy) – zsero

0

CreateProcess has a 32kb limit

lub, jeśli chcesz przejść przez powłokę,

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

Możesz użyć iterators do iteracji przez pod-części problemu. Wykorzystanie iteratory jest podobna do wskaźniki do elementów vector

Co chcesz na zdjęcia nie mogą być realizowane jako funkcja

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

Czy myślałeś o użyciu programu xargs. To może być rozwiązanie wysokiego poziomu rozwiązania problemu.

+0

Używa * Windows * – spraff

+2

Używam narzędzi "unix" na moich maszynach Windows cały czas. kasy: unxutils.sf.net i/lub www.cygwin.com – Mike

+0

Dzięki za podpowiedź, chociaż obawiam się, że to nie pomoże mu uruchomić kodu na * komputerze innej osoby * :-P – spraff

1

Nie trzeba tworzyć nowe sub-wektorów, użyć czegoś podobnego następujące:

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

nadzieję, że to pomaga.

+0

Brandon, co powrócić ProcessSubVec? nie zrozumiałem tego. –

4

Oto moje rozwiązanie:

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

Korzystanie z przykładu Yury: https://onlinegdb.com/rkYRK-raW – CodeGuyRoss

0

Można by utworzyć szablon, który zwraca std :: vector < std :: vector> i odbiera wektor chcesz podzielić, a liczba podziałów. używanie dla i iteratora jest bardzo łatwe.

#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; 
} 
Powiązane problemy