Создание вектора из компонентов, содержащихся в другом типе вектора - PullRequest
4 голосов
/ 03 августа 2009

У меня есть код, который выглядит примерно так:

struct First
{
    int f1;
    int f2;
};

struct Second
{
    First s1;
    int s2;
};

std::vector < Second > secondVec;

Second sec;
sec.s1 = First(); 

secondVec.push_back(sec);
secondVec.push_back(sec);

std::vector < First > firstVec;
firstVec.reserve(secondVec.size());

for (std::vector < Second >::iterator secIter = secondVec.begin(); 
         secIter != = secondVec.end();
         ++secIter)
{
    firstVec.push_back(secIter->s1);
}

Я бы хотел заменить этот уродливый цикл for простой функцией stl, которая могла бы выполнить эквивалентный процесс. Я думал, что, возможно, std::transform может помочь мне здесь, но я не уверен, как это можно написать.

Мне также было бы интересно, если бы boost мог что-нибудь предложить здесь.

Ответы [ 4 ]

7 голосов
/ 03 августа 2009

Если у вас есть TR1 или Boost, вы можете попробовать это:

std::transform(secondVec.begin(),
               secondVec.end(),
               std::back_inserter(firstVec),
               std::tr1::bind(&Second::s1, _1));
5 голосов
/ 03 августа 2009

Определите функтор, который будет преобразовывать второй в первый:

struct StoF { First operator()( const Second& s ) const { return s.s1; } };

Затем используйте его следующим образом:

transform( secondVec.begin(), secondVec.end(), back_inserter(firstVec), StoF() );

Если ваш исходный вектор содержит много элементов, вам следует изменить его размер, чтобы он работал быстрее, как в ответе @Goz:

firstVec.resize( secondVec.size() );
transform( secondVec.begin(), secondVec.end(), firstVec.begin(), StoF() );
3 голосов
/ 03 августа 2009

Это не особенно сложно ... Я попробовал это, и это работало без проблем.

struct First
{
    int f1;
    int f2;
};

struct Second
{
    First s1;
    int s2;
};

First Replace( Second& sec )
{
    return sec.s1;
}

, а затем использовал следующий код, чтобы скопировать его

std::vector < Second > secondVec;

Second sec;
sec.s1.f1 = 0; 
sec.s1.f2 = 1; 
secondVec.push_back(sec);

sec.s1.f1 = 2; 
sec.s1.f2 = 3; 
secondVec.push_back(sec);

std::vector < First > firstVec;
firstVec.resize( secondVec.size() );
std::transform( secondVec.begin(), secondVec.end(), firstVec.begin(), Replace );
2 голосов
/ 03 августа 2009

Вы были правы с вашей интуицией. Хотя вы используете пустой вектор, вы должны использовать обратный вставщик для выходного итератора.

Это должно выглядеть примерно так:

std::transform(secondVec.being(), secondVec.end(), back_inserter(firstVec), yourFunctor)

И ваш Функтор выглядит так:

void youFunctor(First param)
{
  return param.s1;
}

Редактировать: Boost может помочь вам с лямбда-функцией, поэтому вам не придется создавать отдельный функтор для этой задачи. Следует также отметить, что функция лямбда-функции является частью TR1 и будет интегрирована в стандартную библиотеку C ++.

Редактировать: вот о чем Мередит говорила с mem_fun (или адаптером функции-члена).

 struct Second
{
    First s1;
    int s2;
    First getS1() const {return s1;};
};

И тогда преобразование будет выглядеть так:

std::transform(secondVec.being(), 
               secondVec.end(), 
               std::back_inserter(firstVec), 
               std::mem_fun(&Second::getS1))
...