Probleme bei Stringbearbeitung
-
eSsThehelL schrieb:
23:24:28:10:29:18:12:24:11:27:10:22:10:20:28
soll
28:20:10:22:...
werden. Daher kann nicht einfach ein reverse machen. Deswegen ist mein Code etwas komplizierter. Sieht jemand das Problem?
Sollte doch nur eine kleine Änderung in deinem Code sein sein, nicht?
Nein, das macht ein vernünftiger Mensch so wie knivil gesagt hat. Die Streamlösung zielt voll auf formatierte Interpretation der Zahlen ab.
und als Demonstration für Skym0sh0, wie es ohne drei Umwege und trotzdem universell gehen könnte. Damit ist das eine ganz wunderbare Lösung, die kaum einen Prozessortakt zu viel verschwendet, dabei aber universell auf viele Probleme angewandt werden kann.

Ich habe mal deine Lösung mitstd::string foo = "!nebeirhcseg streawkceur remmi nedrew netfahcstoB ehcsinataS"; for (int i=0; i<20; i++) foo = foo + foo;getestet und ich erhalte:
reverse string + streambuf: 3.30s user 0.16s system 99% cpu 3.467 total seppjs reversed streambuf : 2.93s user 0.10s system 99% cpu 3.034 total iterator + for-loo p : 0.78s user 0.10s system 99% cpu 0.883 totalOooh, wie unerwartet. istream hält einen eigenen buffer, ostream hält einen buffer und formatierter Input ist teuer.
Äpfel und Birnen? Aber selbst da ist es trivial anpassbar, da du unformatierte Lesefunktionen nutzen kannst. Das ist ja gerade die schöne Flexibilität. Oh Wunder, schon ist es gleich schnell.
Meine Aussage: IOstream-Parsen ist sehr langsam und für Nicht-Whitespace-getrennten-Standarddatentypen-Input enorm umständlich. (Bei langsamen Festplatten fällt das Parsen vielleicht weniger ins Gewicht, aber wenn der Input schon im RAM ist, ist stringstream der Tod)
Langsam im Gegensatz zu was? Wie kriegst du formatierte Ausdrücke sonst geparsed? Du vergleichst hier dauernd plumpe, unformatierte Wiedergabe der Zeichen mit formatierten Lesefunktionen. Also volle Bestätigung, dass du überhaupt nicht kapiert hast, was die Streamlösung überhaupt macht.
Zu deiner Lösung meines exotischen Problems: Ähh, du hast es nicht gelöst. Es geht nicht darum, die Zeichen auszugeben. Ich will die Zahlen haben! Wir wollen damit rechnen.
Das ist deine Interpretation fürs Problem.
Nein. Da gibt es nichts zu interpretieren. Die Aufgabe ist es, Zahlen zu parsen
aus beliebiger Iteratorquelleeinem forward_list<char>::const_iterator.Klar ist eine Streamlösung einfacher, wenn wir Parsen wollen. Das war aber nie gefragt.
Wenn du nun beginnst, num_get nachzuprogrammieren: Holzweg. Dann fang ich an, Fließkommazahlen hexadezimal in Scientificschreibweise mit Vorzeichen in die Liste zu packen und es soll immer noch funktionieren. Bitte eine universelle Lösung, die meiner ebenbürtig ist.
Nimmstu std::stoi.
Und die Zeichen bekommst du wie in strtoi?
Ich wiederhole: Wie würdest du die eigentliche (im Gegensatz zur ursprünglichen) Aufgabe von freakC++ lösen?
Siehe oben.
-
SeppJ schrieb:
Äpfel und Birnen? Aber selbst da ist es trivial anpassbar, da du unformatierte Lesefunktionen nutzen kannst. Das ist ja gerade die schöne Flexibilität. Oh Wunder, schon ist es gleich schnell.
Zeig sie doch, deine triviale Anpassung. Ich wüsste nicht, wie das trivial möglich wäre.
-
eSsThehelL schrieb:
SeppJ schrieb:
Äpfel und Birnen? Aber selbst da ist es trivial anpassbar, da du unformatierte Lesefunktionen nutzen kannst. Das ist ja gerade die schöne Flexibilität. Oh Wunder, schon ist es gleich schnell.
Zeig sie doch, deine triviale Anpassung. Ich wüsste nicht, wie das trivial möglich wäre.
Die Änderung wäre im Anwendungscode! Keine Anpassung meines Codes. Dein Schrottvergleich soll keine Äpfel mit Birnen vergleichen. Aber das weißt du auch selber. Du möchtest dich bloß aufspielen.
-
SeppJ schrieb:
eSsThehelL schrieb:
SeppJ schrieb:
Äpfel und Birnen? Aber selbst da ist es trivial anpassbar, da du unformatierte Lesefunktionen nutzen kannst. Das ist ja gerade die schöne Flexibilität. Oh Wunder, schon ist es gleich schnell.
Zeig sie doch, deine triviale Anpassung. Ich wüsste nicht, wie das trivial möglich wäre.
Die Änderung wäre im Anwendungscode! Keine Anpassung meines Codes. Dein Schrottvergleich soll keine Äpfel mit Birnen vergleichen. Aber das weißt du auch selber. Du möchtest dich bloß aufspielen.
Naja, ich bezweifle
1. Dass es annähernd so schnell ist wie der direkte Weg
2. Dass es ein trivialer Anwendungscode wird (der schnellste Weg wäre, wieder über istreambuf_iterator zu gehen)Ich weiss nicht, weshalb du dich so sträubst, deine Behauptungen zu unterlegen. Zumal du es ja offensichtlich schon gemacht hast, um die Geschwindigkeit zu vergleichen.
-
"delimiter" ist ein Klassenattribut
Wie gross ist der Aufwand, es als Funktionsparameter zu uebergeben.
In jeder Software Engineering Vorlesung lernst Du, dass frei in der Welt herumfliegende Funktionen nicht gut sind
Lol, das ist abhaengig von Paradigma und Sprache. Sicher schreiben deine Profs. auch permanent Programme. Fuer C++ gilt das eben nicht. Kannst gerne Artikel von Herb Sutter, Scott Meyers oder Stroustrup konsultieren. Die wissen es besser.
Nichts, aber ich brauche sie nie wieder.
Das gleiche gilt fuer die Methode deiner Klasse.
-
eSsThehelL schrieb:
1. Dass es annähernd so schnell ist wie der direkte Weg
Dann bezweifel eben. Meinungen zählen nicht bei objektiven Fakten.
2. Dass es ein trivialer Anwendungscode wird (der schnellste Weg wäre, wieder über istreambuf_iterator zu gehen)
Wenn du derart schlecht mit Streams umgehen kannst, dass dir dazu nur ein Streamiterator einfällt, dann erklärt das einiges.
Ich weiss nicht, weshalb du dich so sträubst, deine Behauptungen zu unterlegen.
Weil ich dazu deinen Anwendungscode bräuchte. Ich weiß nicht einmal, was du überhaupt genau gemacht hast, außer, dass du formatiertes Lesen mit Direktzugriff verglichen hast. Wie jeder große Experte, der alle Feinheiten verstanden hat.
-
SeppJ schrieb:
Dann bezweifel eben. Meinungen zählen nicht bei objektiven Fakten.
Der "objektive Fakt" ist hier deine Meinung, die völlig frei in der Landschaft steht.
SeppJ schrieb:
Wenn du derart schlecht mit Streams umgehen kannst, dass dir dazu nur ein Streamiterator einfällt, dann erklärt das einiges.
Dann klär mich auf.
SeppJ schrieb:
Ich weiß nicht einmal, was du überhaupt genau gemacht hast, außer, dass du formatiertes Lesen mit Direktzugriff verglichen hast. Wie jeder große Experte, der alle Feinheiten verstanden hat.
Du siehst meinen Code und du hast deinen Code (der auf der 1. Seite). Mein Code macht genau das gleiche, was dein Code macht. Ob sich das jetzt formatiert nennt oder nicht, ist irrelevant. Mein Code nutzt Iteratoren (=schneller) und ist mindestens genauso klar.
// gegeben: SeppJs ausgedachtes Problem std::string foo = "!nebeirhcseg streawkceur remmi nedrew netfahcstoB ehcsinataS"; for (int i=0; i<20; i++) foo = foo + foo; // dein Code std::ostreambuf_iterator<char> out(std::cout); auto& ct = std::use_facet<std::ctype<char>>(std::locale()); auto nospace = [&ct](char c){return !ct.is(std::ctype_base::space, c);}; for (auto it=foo.rbegin(), end=foo.rend(); it != end; *out++ = ' ') it=copy_until(std::find_if(it,end,nospace),end,out,nospace); // Sehr allgemeine Hilfsfunktionen wie dein Streambuf (zählen nicht zum Code) template <typename In, typename Out, typename Pred> In copy_until(In from, In to, Out out, Pred pred) { while (from != to && pred(*from)) *out++ = *from++; return from; }Code mit Streams hat also keinen Vorteil gegenüber Iteratoren. Vor allem, wenn man sich Hilfsfunktionen wie ignore_spaces schreibt. Dann kann Iteratorencode auch Sachen, die Streams nicht wirklich können. Schreib du mal Streamcode für das zweite Problem:
// gegeben: freakC++s Problem std::string foo = "eins:zwei:drei:vier:fuenf:sechs:"; for (int i=0; i<20; i++) foo = foo + foo; foo.pop_back(); // dein Code std::ostreambuf_iterator<char> out(std::cout); for (auto it=foo.rbegin(), end=foo.rend(); it != end;) { auto a = it.base(), b = (it = std::find(it,end, ':')).base(); copy(b, a, out); if (it != end) { ++it; *out++ = ':'; } // Kein ':' am Schluss }
-
Das ist deine Herausforderung?
Ich habe dir solch eine Steilvorlage geliefert, bei der du nur irgendein Beispiel hättest konstruieren brauchen (imho unmöglich, aber wer weiß), um mich zu demütigen und stattdessen beweist du (zum dritten Mal) selber, dass du
-im ersten Beispiel tatsächlich keine Ahnung hast, wie man Streams benutzt und was mein Code überhaupt macht
-im zweiten Beispiel um den heißen Brei redest, weil du nicht verstehst, was mein Code überhaupt machtDa gibt's nichts zu antworten, bevor du deine Hausaufgaben nicht machst. Ich warte immer noch auf eine gleichwertige Implementierung deinerseits, die formatiert aus Iteratorquellen lesen kann. Du verstehst ja anscheinend nicht einmal die Bedeutung davon:
eSsThehelL schrieb:
Ob sich das jetzt formatiert nennt oder nicht, ist irrelevant.
Du verstehst nicht, was mein Code überhaupt macht.
Das hier ist Zeitverschwendung³. Du willst nicht verstehen*.
*: Das ist ein Kompliment. Die Alternative wäre, dass du zu dumm bist.
-
SeppJ schrieb:
Ich warte immer noch auf eine gleichwertige Implementierung deinerseits, die formatiert aus Iteratorquellen lesen kann.
Kannst du konkret sagen, wo das im ersten Beispiel nicht der Fall ist?
-
SeppJ schrieb:
bei der du nur irgendein Beispiel hättest konstruieren brauchen (imho unmöglich, aber wer weiß), um mich zu demütigen
Du persönlich bist mir egal. Ich will die Iostreams demütigen.
-
eSsThehelL schrieb:
Du persönlich bist mir egal. Ich will die Iostreams demütigen.
Na dann auf!
-
eSsThehelL schrieb:
SeppJ schrieb:
Ich warte immer noch auf eine gleichwertige Implementierung deinerseits, die formatiert aus Iteratorquellen lesen kann.
Kannst du konkret sagen, wo das im ersten Beispiel nicht der Fall ist?
An der Stelle an der du einfach Zeichen weiter drückst, ohne auf jedwedes Format zu achten? Es geht bei dem Code nicht darum, Iteratoren zu dereferenzieren und irgendwo hin zu schreiben (Das könnte man auch und man braucht das bei weitem nicht so umständlich wie du zu machen). Es geht darum, dass man Iteratoren->Stream umwandeln kann, so dass man all die tollen Sachen machen kann, die man nur mit Streams machen kann (zum Beispiel Interpretation formatierter Daten), ohne das man jemals Kopien oder gar Mehrfachiteration benötigt (Skym0sh0 auf Seite 1).
Deine Alternativvorschläge können genau diese Kernpunkte nicht erfüllen. Sie können nicht formatiert lesen und dein Rettungsversuch (strtoi) benötigt wieder Kopien (wie bekommst du die Daten in strtoi?) und eventuell sogar Mehrfachiteration (wie trennst du die Tokens?).
Hier ein konkretes Beispiel:
{ std::forward_list<int> foo = {52, 32, 56, 32, 49, 53, 32, 49, 54, 32, 50, 51, 32, 52, 50}; iterator_streambuf<decltype(foo.begin())> buf(foo.begin(), foo.end()); std::istream in(&buf); int sum = 0; for(int i; in >> i; sum += i); std::cout << sum << '\n'; }Mach mal nach. Wenn du das schaffst, dann zeige ich dir auch irgendwann mal get, read & Co, damit du aus Streams unformatiert lesen kannst, ohne istreambuf_iterator-Monstren zu benutzen
. (Du wirst bei letzterem feststellen, dass mein streambuf bloß ein dünner Abstraktionslayer um die Iteratoren ist, so dass diese Aktionen ungefähr genau so schnell wie eine Schleife über die Iteratoren sind. Erst recht, wenn man das noch fehlende xsgetn
mit Zusatzinformationen über den Iteratortyp implementiert.)
-
SeppJ schrieb:
Es geht darum, dass man Iteratoren->Stream umwandeln kann, so dass man all die tollen Sachen machen kann, die man nur mit Streams machen kann (zum Beispiel Interpretation formatierter Daten)
Die "tollen Sachen" sind ziemlich genau auf
Whitespace-getrennten-Standarddatentypen-Input
beschränkt.
Es ist für mich kein Wunder, dass du dich mit deinen Beispielen auf Ints mit Leerzeichen dazwischen beschränkst und dich weigerst, die Aufgabe von freakC++ zu lösen. Vielleicht ist die Schlussfolgerung falsch, aber mit deinem Verhalten bestätigst du mir das nur.
SeppJ schrieb:
ohne das man jemals Kopien oder gar Mehrfachiteration benötigt (Skym0sh0 auf Seite 1).
Iteratoren sind nicht deshalb schlecht, weil sie jemand falsch verwendet. Trotzdem, ich bin fast sicher, dass der schlechte Code von Skym0sh0 schneller als deiner ist, du deinen mit Tuning aber schneller machen könntest.
SeppJ schrieb:
Deine Alternativvorschläge können genau diese Kernpunkte nicht erfüllen. Sie können nicht formatiert lesen und dein Rettungsversuch (strtoi) benötigt wieder Kopien (wie bekommst du die Daten in strtoi?) und eventuell sogar Mehrfachiteration (wie trennst du die Tokens?).
Mehrfachiteration brauchen nur die Streams, weil die grundlos einen internen Buffer halten. Mit Streams hast du im prinzip einen limitierten Inputiterator, sobald du für etwas Mehrfachiteration brauchst, muss das jedesmal gecached werden.
SeppJ schrieb:
Hier ein konkretes Beispiel:
Wo ist der Erkenntnisgewinn?
auto& ct = std::use_facet<std::ctype<char>>(std::locale()); int sum = 0; for (auto it=foo.begin(), end=foo.end(); it != end;) sum += parse<int>(it, end, it, ct); std::cout << sum << '\n'; // wobei template <typename T, typename In, typename Facet> T parse(In from, In to, In& next, Facet& ct, int base=10) { // Facet nur um SeppJ zufriedenzustellen ("formatiert") auto nospace = [&ct](char c){return !ct.is(std::ctype_base::space, c);}; auto isdigit = [&ct](char c){return ct.is(std::ctype_base::digit, c);}; std::string buf; char *p; next=copy_until(std::find_if(from,to,nospace),to,std::back_inserter(buf),isdigit); T t = strtol(buf.c_str(), &p, base); if (p == buf.c_str()) throw std::invalid_argument(""); return t; }Das ist genau das gleiche wie das mit Strings, nur dass leider keine parse-Funktion für Iteratoren gibt.
Davon abgesehen ist der Code immer noch um Faktor 5 schneller als deiner mit den Streams. Ein Aufruf einer virtuellen Funktion macht das kopieren eines chars wett.
SeppJ schrieb:
Wenn du das schaffst, dann zeige ich dir auch irgendwann mal get, read & Co, damit du aus Streams unformatiert lesen kannst, ohne istreambuf_iterator-Monstren zu benutzen
.Zeig mal. Meine Beispiele hast du ja.
SeppJ schrieb:
(Du wirst bei letzterem feststellen, dass mein streambuf bloß ein dünner Abstraktionslayer um die Iteratoren ist
lol. Ja, dein streambuf schon. Aber das ganze drumherum ist alles andere als dünn.
-
eSsThehelL schrieb:
Es ist für mich kein Wunder, dass du dich mit deinen Beispielen auf Ints mit Leerzeichen dazwischen beschränkst
Um die Beispiele einfach zu halten
. Ich kann auch gerne einen selbstdefinierten operator>> nehmen. Bin mal gespannt, wie du damit zurecht kämst.und dich weigerst, die Aufgabe von freakC++ zu lösen.
Aufmerksamer Leser
FreakC++: Ich will A
Skym0sh0: Hier eine Lösung L(A) für A
SeppJ: Das geht besser. Hier eine Lösung L2(A) für A. Die ist dafür superplusgut.
FreakC++: Ich will aber B
knivil, SeppJ und andere: Dafür nimmt man L(B). Das ist dafür superplusgut.Du: SeppJ, dein L2(A) geht nicht auf B! Du bist doof! Wähwähwäh! qq! Wenn du B nicht mit L2(A) löst, dann geh ich zu meiner Mama!

SeppJ schrieb:
ohne das man jemals Kopien oder gar Mehrfachiteration benötigt (Skym0sh0 auf Seite 1).
Iteratoren sind nicht deshalb schlecht, weil sie jemand falsch verwendet. Trotzdem, ich bin fast sicher, dass der schlechte Code von Skym0sh0 schneller als deiner ist, du deinen mit Tuning aber schneller machen könntest.
Nein, ist er nicht.
SeppJ schrieb:
Hier ein konkretes Beispiel:
Wo ist der Erkenntnisgewinn?
Du könntest etwas lernen. Aber ja, diese Hoffnung besteht nicht wirklich.
Das ist genau das gleiche wie das mit Strings, nur dass leider keine parse-Funktion für Iteratoren gibt.
Ach! Man könnte meinen, dass dies the whole fucking point war! Was soll man danach noch sagen? Doppeldenk?