2013-09-05 20 views
5

Rozważmy następujący:C++ std Kopiowanie listę map

struct A 
{ 
    int i; 
    double d; 
    std::string s; 
}; 

std::list<A> list_A; 

Chciałbym skopiować wszystkie elementy list_A na mapie tak, że każda para na mapie składa się z elementu z list_A jako wartość i jej ciąg s jako klucz. Czy istnieje sposób na to, że jest bardziej elegancki niż zapętlenie listy i wstawienie każdego elementu wraz z jego ciągiem jako kluczem do mapy?

+5

Dla mnie pętla jest najlepiej czytelnym i najbardziej pomocnym rozwiązaniem. –

+1

Możesz coś zrobić z ['std :: transform'] (http://en.cppreference.com/w/cpp/algorithm/transform). – juanchopanza

+0

Możesz użyć standardowej pętli 'for' lub' ranged-based for'. Jeśli zamiast tego użyjesz standardowego algorytmu bibliotecznego, będziesz pisać ten sam korpus pętli i pakować go do obiektu funkcji lub lambda, aby przejść do algorytmu. Osobiście, dla czegoś tak prostego myślę, że pętla 'range-based for' jest" lepsza ". – Blastfurnace

Odpowiedz

6

To powinno Ci się pomysł jak wykorzystać transform:

std::pair<std::string, A> pairify(const A& a) { return std::make_pair(a.s, a); } 

std::transform(list.begin(), list.end(), std::inserter(map, map.end()), pairify); 

reason to use the inserter jest:

Wkładka interator to specjalny rodzaj wyjściowego iteratora zaprojektowany, aby umożliwić algorytmów które zwykle zastępują elementy (takie jak kopie), aby zamiast tego wstawiać nowe elementy automatycznie w określonej pozycji w kontenerze.

+0

I działa dobrze :) –

+0

I wiem, że nie pytałem o efektywność, ale jestem ciekawostką: czy w ten sposób jest to również skuteczniejsze niż zapętlenie wszystkich elementów i wstawienie ich na mapę? – Subway

1

Przepraszamy za ostatnią odpowiedź zbyt szybko bez szczegółów, tutaj jest kod do kompilacji.

struct A 
{ 
    int i; 
    double d; 
    std::string s; 
}; 

std::list<A> list_A; 

std::pair<std::string, A> convert(const A &x) { 
    return make_pair(x.s,x); 
} 

int main() { 

    std::map<std::string,A> out; 

    std::transform(list_A.begin(), list_A.end(), std::inserter(out,out.end()),convert); 

} 
+0

Nie ... Po pierwsze, mapa wymaga dwóch parametrów szablonu, a po drugie nie można zainicjować mapy, aby mieć ten sam rozmiar listy. – LarryPel

+0

Również transformacja zrobi coś takiego: * map_iterator = functionToCopyStructToList(); i nie można "przypisać" iteratora mapy w ten sposób ... ten kod się nie skompiluje – LarryPel

+0

Obaj macie rację, właśnie dałem konspekt po raz pierwszy bez wszystkich szczegółów – jayadev

0

może przechowywać go w set: w ten sposób nie byłoby powielanie danych na mapie (s sama):

struct A 
{ 
    bool operator < (const A& r_) const { return (s < r_.s); } 
    int i; 
    double d; 
    std::string s; 
}; 

std::list<A> list_A; 
std::set<A> set_A; 

for (std::list<A>::const_iterator itr = list_A.begin(); itr != list_A.end(); ++itr) { 
    if (! set_A.insert(*itr).second) { 
     // Handle duplicated elements 
    } 
} 

mogę zachować pętli: w ten sposób można obsłużyć poprawnie powielono elementy.

0

Jeśli używasz C++ 11 można użyć funkcji lambda z wychwytem:

std::map<std::string, A> m; 
std::list<A> l; 
std::for_each(l.begin(), l.end(), 
       [&](const A& a) { 
        m.insert(std::make_pair(a.s, a)); 
       }); 
4

kocham standardowych algorytmów bibliotecznych oraz lambdy ale nie ma się o wiele prostsze niż:

for (const A& value : list_A) { 
    map_A.insert(std::make_pair(value.s, value)); 
} 

Inne metody wykonują ekwiwalent tego kodu, a ta pętla jest czytelna i równie szybka.

+0

Myślę, że ten facet nie jest dla prostoty :). –

Powiązane problemy