Как написать этот цикл for используя std :: for_each или std :: transform? - PullRequest
2 голосов
/ 21 января 2011

Это больше вопрос обучения.Есть ли способ написать следующий цикл for, используя std :: for_each или std :: transform?Если нет, то есть ли что-то, что может помочь в этом?Цикл просто сплющивает вектор векторов в один длинный вектор.

vector<vector<int> > int_vectors;

// ... fill int_vectors

vector<int> ints;

for (vector<vector<int> >::const_iterator iter = int_vectors.begin(); iter != int_vectors.end(); ++iter) {
   ints.insert(ints.end(), iter->begin(), iter->end());
}

Ответы [ 3 ]

4 голосов
/ 21 января 2011

Я бы не стал использовать один из алгоритмов, если у вас нет компилятора, который поддерживает лямбды. Это совершенно ясно, как написано. Даже если ваш компилятор поддерживает лямбды, я бы, вероятно, не изменил этот код.

Одним из относительно простых вариантов было бы написать уплощающий итератор. Я написал один для демонстрации в ответ на другой вопрос .

Если вы действительно хотите использовать однострочник и можете использовать bind (boost::bind от Boost, std::tr1::bind от TR1 и std::bind от C ++ 0x будут работать), тогда вот как это будет выглядеть. Заранее предупреждаю: это ужасно.

Редактировать: Технически это также незаконно. Тип функции-члена стандартной библиотеки не указан, поэтому вы не можете (переносимо или правильно) взять адрес такой функции-члена. Если бы вы могли правильно взять адрес функции-члена стандартной библиотеки, это выглядело бы так:

typedef std::vector<int>::iterator (std::vector<int>::*IteratorGetter)();

std::for_each(int_vectors.begin(), int_vectors.end(),
    std::bind(
        std::bind(
            &std::vector<int>::insert<std::vector<int>::iterator>, 
            &ints, 
            std::bind((IteratorGetter)&std::vector<int>::end, &ints), 
            _1, 
            _2
        ),
        std::bind((IteratorGetter)&std::vector<int>::begin, _1),
        std::bind((IteratorGetter)&std::vector<int>::end, _1)
    )
);

(Да, технически это одна «строка кода», так как это один оператор. Единственное, что я извлек - это typedef для типа указатель на член-функцию, используемый для устранения неоднозначности перегруженного begin и end функции; вам необязательно указывать это, но код требует горизонтальной прокрутки при переполнении стека, если я этого не сделаю.)

2 голосов
/ 21 января 2011

Если ваш компилятор поддерживает лямбды, это довольно просто. Typedefs помогают с удобочитаемостью.

typedef std::vector<int> VI;
typedef std::vector<VI> VVI;

VVI int_vectors;
VI ints;

std::for_each(int_vectors.begin(), int_vectors.end(), [&](VI &vec) {
    ints.insert(ints.end(), vec.begin(), vec.end());
});
0 голосов
/ 22 января 2011

Я знаю, что макросы не очень хорошая практика, но вы можете делать с ними некоторые умные вещи:

#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

using namespace std;
#define all(v) (v).begin(), (v).end()
#define foreach(it, v) for(auto it = (v).begin(); it != (v).end(); ++it)

void main() {
    vector<int> vi;
    vector<vector<int>> vvi;

    foreach(it, vvi) {
        copy(all(*it), back_inserter(vi));
    }
}

Вы также можете использовать std :: copy и back_inserter, чтобы делать то, что вы пытаетесь достичь.

...