2015-10-22 3 views
5

У меня естьКак использовать алгоритмы для заполнения вектора векторов

typedef std::vector<int> IVec; 
typedef std::vector<IVec> IMat; 

, и я хотел бы знать, как я могу заполнить IMat с помощью алгоритмов Std, то есть, как сделать следующее с меньшим количеством коды (все IVec s имеют одинаковый размер)?

void fill(IMat& mat){ 
    for (int i=0;i<mat.size();i++){ 
     for (int j=0;j<mat[i].size();j++){ 
      mat[i][j] = i*j; 
     } 
    } 
} 

PS: уже способ заполнить матрицу константой поможет мне. И желательно с алгоритмами pre-C++ 11.

+2

Sice значения зависят от индексов ... просто оставайтесь с петлями. – deviantfan

+1

Нужно ли инициализировать пустые векторы или заполнить значения векторов, которые уже не пустые? Кроме того, вы хотите заполнить их индексами ('i * j') или любое значение (например,' 0') будет делать? – SingerOfTheFall

+0

@SingerOfTheFall Не уверен, что если я понимаю ваш первый вопрос, мой IMath уже инициализирован, то есть не пуст. Да, значения должны зависеть от индексов. Однако это уже помогло бы мне заполнить его константой. – user463035818

ответ

3

Я не знаю, если это лучше, чем двойной цикл, но один из возможных способов вы можете сделать это с помощью STL в C++ 11 будет использовать два for_each следующим образом:

int i(0); 
std::for_each(mat.begin(), mat.end(), 
[&i](IVec &ivec){int j(0); std::for_each(ivec.begin(), ivec.end(), 
          [&i,&j](auto &k){k = i*j++;}); ++i;}); 

LIVE DEMO

+2

Я уверен, что порядок генерации не гарантируется => в зависимости от реализации, вы заполняете неправильные значения. – deviantfan

+0

@deviantfan не знал, что удивление тогда. – 101010

+1

@deviantfan Можете ли вы дать какие-либо доказательства, подтверждающие это? http://en.cppreference.com/w/cpp/algorithm/generate#Possible_implementation реализует его как: 'while (first! = last) * first ++ = g();'. Я полагал, что * все * алгоритмы итератора были последовательными. Там может быть много проблем, например, с лямбдами, если это не так. –

5

Лучшее решение - это тот, который вы уже реализовали. Он использует преимущества i/j как в смещениях, так и в качестве входных данных для вычисления алгоритма.

Стандартные алгоритмы должны использовать итераторы для элементов и поддерживать счетчики. Это зеркалирование данных как верный признак проблемы. Но это может быть сделано, даже на одной линии, если вы хотите быть фантазии:

for_each(mat.begin(), mat.end(), [&](auto& i) { static auto row = 0; auto column = 0; generate(i.begin(), i.end(), [&]() { return row * column++; }); ++row; }); 

Но, как указано просто привести это может быть сделано, не означает, что это должно быть сделано. Лучший способ приблизиться к этому - for -loop. Даже делая это на одной линии, возможно, если это ваша вещь:

for(auto i = 0U;i < mat.size();i++) for(auto j = 0U;j < mat[i].size();j++) mat[i][j] = i*j; 

Кстати мой стандартный алгоритм отлично работает на Clang 3.7.0, gcc 5.1, и на Visual Studio 2015. Однако previously I used transform rather than generate. И, похоже, есть implementation bugs in gcc 5.1 and Visual Studio 2015 с захватами лямбда-области static переменных.

+0

, если он подходит, накладывать вещи на одну строку - это очень «моя вещь», но если бы мне пришлось решать, то исключение '{}' вокруг тела цикла for было бы запрещено;) – user463035818

+0

@ tobi303 Поскольку новые строки бесплатны Я использую их в своем личном коде. (Наряду с фигурными скобками.) Я думаю, что это делает его более читаемым. Но в конце дня я считаю, что самым важным решением в этом случае является не то, чтобы сделать это на одной строке, но и сделать это в 'for'-loop. –

+2

+1 только за это утверждение: «Но, как было заявлено, просто потому, что это можно сделать, это не значит, что это должно быть сделано» –

3

Просто подумал, что я прокомментирую отличный ответ Джонатана.

Игнорируйте синтаксис C++ 11 и предположите, что мы написали несколько вспомогательных классов (не имеет значения, как сейчас).

мы, вероятно, может придумать код, как это:

auto main() -> int 
{ 
    // define a matrix (vector of vectors) 
    IMat mat; 

    // resize it through some previously defined function 
    resize(mat, 10, 10); 

    // get an object that is a pseudo-container representing its extent 
    auto extent = extent_of(mat); 

    // generate values in the pseudo-container which forwards to the matrix 
    std::generate(extent.begin(), 
        extent.end(), 
        [](auto pxy) { pxy.set_value(pxy.x * pxy.y); }); 

    // or even 

    for (auto pxy : extent_of(mat)) { 
     pxy.set_value(product(pxy.coordinates())); 
    } 

    return 0; 
} 

100 строк кода поддержки позже (Iterable контейнеры и их доверенные лица не являются тривиальными), и это будет компилировать и работать.

Clever, как это, несомненно, будет, есть некоторые проблемы:

  • Там в небольшой вопрос 100 дополнительных строк кода.
  • Мне кажется, что этот код на самом деле меньше выразительный, чем ваш. т. е. сразу видно, что делает ваш код. С моим вы должны сделать некоторые предположения или пойти и рассуждать о дополнительных 100 строках кода.
  • мой код нужен много больше обслуживания (и документации), чем ваш

Иногда меньше больше.

Смежные вопросы