2015-08-21 2 views
0

Используя C++ с boost/stl, как я могу объединить два списка разных объектов, скажем, A и B? Они имеют некоторые общие и некоторые разные поля/свойства и не имеют уникального идентификатора.Как слить два контейнера (векторы/списки) разных структур, но с одним общим параметром в C++

class A 
{ 
    int id; 
    double smth; 
} 

class B 
{ 
    int id; 
    std::string name; 
    Type type; 
} 

class C 
{ 
    int id; 
    std::string name; 
    Type type; 
    double smth; 
} 

Так что идея в том, что у меня есть, например, std::list<A> и std::list<B>, и я хочу легко объединить их с std::list<C>

+0

Как вы строите 'C' из' A', является 'id' идентификатором, поэтому, если' a.id == b.id', 'C' нужно построить из' a' и 'b'? – Jarod42

+0

@ Jarod42, я думаю 'a.id! = B.id' всегда. Я основываю это на «... не делясь уникальным идентификатором» –

ответ

0

Кажется, что вы хотите получить JOIN (--as это называется в SQL). Выполните следующие действия:

  • Сортируйте оба списка по id.
  • Переверните оба и объедините их - здесь действительная процедура отличается от того, хотите ли вы INNER, LEFT, RIGHT или FULL OUTER JOIN. Я предполагаю, что вы хотите INNER JOIN, то есть: включить переменную в std::list<C> только в том случае, если существуют как id.

Вот небольшой код для достижения этой цели:

auto compare = [](auto const& u, auto const& v) { return u.id < v.id;}; 

std::list<A> a; 
a.sort(compare); 
std::list<B> b; 
b.sort(compare); 

std::list<C> c; 
auto ita = std::begin(a); 
auto itb = std::begin(b); 
while(ita != std::end(a) && itb != std::end(b)) 
{ 
    if(ita->id == itb->id) 
    { 
     c.emplace_back(*ita, *itb); 
     ++ita; 
     ++itb; 
    } 
    else if(ita->id < itb->id) 
    { 
     ++ita; 
    } 
    else 
    { 
     ++itb; 
    }   
} 

Для работы необходимо также конструктор в C который сливает A и B:

C(A const& a, B const& b) : /* assign the stuff */ {} 

Demo. Он компилируется и должен работать, но он не проверен.

1

Предоставьте адаптер/конвертер и используйте его.

struct Type{}; 

struct A 
{ 
    int id; 
    double smth; 
}; 

struct B 
{ 
    int id; 
    std::string name; 
    Type type; 
}; 

struct C 
{ 
    int id; 
    std::string name; 
    Type type; 
    double smth; 

    C(const B& b) : id(b.id), name(b.name), type(b.type){} 
    C(const A& a) : id(a.id), smth(a.smth) {} 
}; 

int main() { 

    std::vector<A> a = {{5, 0.6f}, {3, 0.3f}}; 
    std::vector<C> c; 
    c.insert(c.end(), a.cbegin(), a.cend()); 
    return 0; 
} 
+1

Возможно, вы захотите инициализировать неиспользуемые элементы. По крайней мере, без инициализации по умолчанию (например, 'smth' при преобразовании из B). –

0

Вы можете использовать преобразование с помощью простого функтора:

Live On Coliru

enum Type { T1,T2,T3,TA }; 

struct A 
{ 
    int id; 
    double smth; 
}; 

struct B 
{ 
    int id; 
    std::string name; 
    Type type; 
}; 

struct C 
{ 
    int id; 
    std::string name; 
    Type type; 
    double smth; 
}; 

struct MakeC { 
    C operator()(A const& a) const { return { a.id, "",  TA,  a.smth }; } 
    C operator()(B const& b) const { return { b.id, b.name, b.type, 0.0 }; } 
}; 

#include <iterator> 
#include <algorithm> 

int main() { 
    std::vector<A> as(10); 
    std::vector<B> bs(10); 

    std::vector<C> cs; 

    std::transform(as.begin(), as.end(), back_inserter(cs), MakeC()); 
    std::transform(bs.begin(), bs.end(), back_inserter(cs), MakeC()); 
} 
Смежные вопросы