Liste mit maps sortieren
-
Ein erster Schritt sollte immer einen Blick in die C++ Referenz sein:
https://en.cppreference.com/w/cpp/container/list/sort
Die Sortierungsfunktion erlaubt die Angabe einer Vergleichsfunktion. Und diese würde ich ausprobieren.
-
die Liste ist ein Teil der Konfiguration (BIN) meiner Website. So wird sie erstellt:
void Folder(Response &r){ list < map<string,string> > slice; for( auto li = r.BIN.begin(); li != r.BIN.end(); li++){ string url = li->first; map <string,string> hunt = r.BIN[url]; if( hunt["parent"].compare(r.URL) == 0 ){ hunt["url"] = url; slice.push_back(hunt); } } r.LOOPS["children"] = slice; }
Die map (hunt) hat mehrere name/value Paare wie title, descr. Damit wird ein Template gerendert, das Ergebnis ist HTML: http://rolfrost.de/cpp.chtml
und das soll nach title sortiert werden.MFG
Nur zum Verständnis, das Template
<dl> `loop_children` <dt class='file'> <a href="`url`" class="outlink"> `title` </a> </dt> <dd> `descr` </dd> `endloop` </dl>
-
Generell, ohne weiter auf deinen Code einzugehen:
Verwende std::vector statt std::list. Vector ist eine Art Array mit Größenangabe, das automatisch wachsen kann, während list eine verkettete Liste ist. List habe ich tatsächlich noch nie produktiv benutzt, da vector praktisch immer besser ist. (Ich habe aber nicht weiter auf deinen Code geguckt, da kommt mir mehr komisch vor, u.a. vermute ich, dass BIN auch ne map ist, aber dann könntest du second für den map-Wert nutzen statt über eckige Klammern first nachzugucken. Siehe außerdem https://en.cppreference.com/w/cpp/language/structured_binding um first/second gleich lesbar zu machen)
-
@_ro_ro Erstmal denke ich, dass, wie @wob geschrieben hat, ein Vektor oder direkt eine Map besser geeignet ist.
Was das sortieren betrifft, wenn ich dich richtig verstanden habe:
std::sort( std::begin(slice), std::end(slice), [](const map<string,string>& a, const map<string, string>& b) { return a["title"] < b["title"]; } );
bzw, ich würde
std::sort( std::begin(slice), std::end(slice), [](const auto& a, const auto& b) { return a["title"] < b["title"]; } );
Unabhängig davon, ob slice jetzt eine
list
oder einvector
ist.Ich habe das gerade aber nicht getestet.
-
danke Dir,
C:\var\www\vhosts\rolfrost.de\httpdocs\cgi-bin\fw.cpp: In lambda function: C:\var\www\vhosts\rolfrost.de\httpdocs\cgi-bin\fw.cpp:588:31: error: passing 'const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >' as 'this' argument discards qualifiers [-fpermissive] return a["title"] < b["title"]; ^ In file included from c:\mingw6.2\lib\gcc\mingw32\6.3.0\include\c++\map:61:0, from C:\var\www\vhosts\rolfrost.de\httpdocs\cgi-bin\fw.cpp:9: c:\mingw6.2\lib\gcc\mingw32\6.3.0\include\c++\bits\stl_map.h:494:7: note: in call to 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = std::__cxx11::basic_string<char>; _Tp = std::__cxx11::basic_string<char>; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::__cxx11::basic_string<char>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::__cxx11::basic_string<char>]' operator[](key_type&& __k) ^~~~~~~~
entweder fehlt eine
#include <???>
oder meine C++ Version 201402 gibt das nicht her.Viele Grüße!!
-
@_ro_ro nutze map.at statt map[], weil die eckigen Klammern die map ändern können, passen sie nicht mit const zusammen.
-
Hups, was @wob sagt. Und,
std::sort
ist im Header<algorithm>
-
ich verstehe nur Bahnhof. Also ich habe jetzt eine dedizierte sort-Funktion
bool title_sort(map<string,string>& a, map<string, string>& b){ return a["title"] < b["title"]; }
Aber wenn ich sie aufrufe
sort(slice.begin(), slice.end(), title_sort);
gibts jede Menge FehlermeldungenIn file included from c:\mingw6.2\lib\gcc\mingw32\6.3.0\include\c++\algorithm:62:0, from c:\mingw6.2\lib\gcc\mingw32\6.3.0\include\c++\regex:38, from C:\var\www\vhosts\rolfrost.de\httpdocs\cgi-bin\fw.cpp:18: c:\mingw6.2\lib\gcc\mingw32\6.3.0\include\c++\bits\stl_algo.h: In instantiation of 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = std::_List_iterator<std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&, std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&)>]': c:\mingw6.2\lib\gcc\mingw32\6.3.0\include\c++\bits\stl_algo.h:4739:18: required from 'void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = std::_List_iterator<std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >; _Compare = bool (*)(std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&, std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&)]' C:\var\www\vhosts\rolfrost.de\httpdocs\cgi-bin\fw.cpp:588:48: required from here c:\mingw6.2\lib\gcc\mingw32\6.3.0\include\c++\bits\stl_algo.h:1966:22: error: no match for 'operator-' (operand types are 'std::_List_iterator<std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' and 'std::_List_iterator<std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >') std::__lg(__last - __first) * 2, ~~~~~~~^~~~~~~~~
-
@_ro_ro sagte in Liste mit maps sortieren:
ich verstehe nur Bahnhof.
Du darfst nicht
a["title"] < b["title"]
schreiben, sondern mussta.at("title") < b.at("title")
schreiben.Also ich habe jetzt eine dedizierte sort-Funktion
Edit: Ach, ich hatte gehofft, du hättest schon auf vector statt list umgestellt.
-
Für eine
list<...>
funktioniert std::sort nicht (anders als @Schlangenmensch geschrieben hat), denn es verlangt einenRandomAccessIterator
(also direkten Indexzugriff), daher hat diese eine eigene sort Funktion.
-
@wob sagte in Liste mit maps sortieren:
...
Verwende std::vector statt std::list.
...@_ro_ro
Das solltest du wirklich tun.
-
ne, da muss ich ja meine ganze Template-Klasse ändern. Aber wenn
list
schon eine eigene Sortierfunktion hat, muß es doch möglich sein, nach "title" sortieren zu können. In Perl ist das eine einzige Zeile seufz.MFG
-
Oooops, kaum macht mans richtig
bool title_sort(map<string,string>& a, map<string, string>& b){ return a["title"] > b["title"]; } void Folder(Response &r){ list < map<string,string> > slice; for( auto li = r.BIN.begin(); li != r.BIN.end(); li++){ string url = li->first; map <string,string> hunt = r.BIN[url]; if( hunt["parent"].compare(r.URL) == 0 ){ hunt["url"] = url; slice.push_back(hunt); } } slice.sort(title_sort); r.LOOPS["children"] = slice; }
Isses das auch? Wenn ich den Vergleichsoperator rumdrehe. wird auch andersherum sortiert.
MFG
-
@_ro_ro
In C++ auch:slice.sort( []( const map<string,string>& lhs, const map<string, string>& rhs ) { return lhs.at( "title" ) < rhs.at( "title" ); } );
Edit 1
Waren wir vorhin nicht sogar schon bei const-correctness?Edit 2
@wob ouch, fixed
-
at
ist eine Funktion und braucht runde Klammern. Edit: ist oben schon gefixt.
-
Ahh, danke!!! Und danke Euch!
Viele Grüße
PS: Daß list eine sort-Methode hat war der entscheidende Hinweis!
-
@_ro_ro sagte in Liste mit maps sortieren:
ne, da muss ich ja meine ganze Template-Klasse ändern.
slice wird doch nur lokal benutzt, wieso musst du dann alles ändern?
@_ro_ro sagte in Liste mit maps sortieren:
Aber wenn
list
schon eine eigene Sortierfunktion hat, muß es doch möglich sein, nach "title" sortieren zu können. In Perl ist das eine einzige Zeile seufz.Du hast dich nun mal entschieden, das in C++ zu machen. Das Gejammere, dass es in <hier beliebige Programmiersprache einsetzen> einfacher, besser oder schneller geht hilft keinem weiter. Wenn es in anderen Programmiersprachen besser, schneller oder einfacher geht, warum machst du dann C++?
-
@DocShoe sagte in Liste mit maps sortieren:
slice wird doch nur lokal benutzt
Ja schon. Aber meine
Templating::Loop
funktioniert nunmal auch nur mit bestimmten DatentypenIm Übrigen hat meine Anmerkung mit Jammern nicht das Geringste zu tun.
MFG
-
Ouch, ja, sehe grad, dass du die in
r
einsetzt. Du solltest dir trotzdem überlegen, ob du das nicht trotzdem überarbeiten möchtest.std::vector
ist der Wald- und Wiesen-Sequence-Container in C++, man sollte schon gute Gründe haben, stattdessen einen anderen Containertyp zu benutzen.
-
@Th69 Argh...
std::list
gehört zu den Containern, mit denen ich tatsächlich noch nie gearbeitet habe, man sollte halt doch alles einmal in nen Compiler jagen.