Optimierung der Aggregate für String Concatenation

stimmen
18

Update - für die Ergebnisse eines facetious Rahmen des Geistes, können Sie davon ausgehen , dass Aggregate noch das normale Ergebnis führt , was Funktion an sie übergeben wird, auch im Fall optimiert.

Ich schrieb dieses Programm, um eine lange Reihe von ganzen Zahlen von 0 bis 19.999 separates bauen durch Kommas.

using System;
using System.Linq;
using System.Diagnostics;

namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            const int size = 20000;

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            Enumerable.Range(0, size).Select(n => n.ToString()).Aggregate((a, b) => a + ,  + b);
            stopwatch.Stop();

            Console.WriteLine(stopwatch.ElapsedMilliseconds + ms);
        }
    }
}

Wenn ich es laufen, heißt es:

5116ms

Mehr als fünf Sekunden schrecklich. Natürlich ist es, weil die ganze Schnur um die Schleife jedes Mal kopiert wird.

Was aber, wenn man sehr kleine Änderung durch den Kommentar angezeigt machen?

using System;
using System.Linq;
using System.Diagnostics;

namespace ConsoleApplication5
{
    using MakeAggregateGoFaster;  // <---- inserted this

    class Program
    {
        static void Main(string[] args)
        {
            const int size = 20000;

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            Enumerable.Range(0, size).Select(n => n.ToString()).Aggregate((a, b) => a + ,  + b);
            stopwatch.Stop();

            Console.WriteLine(stopwatch.ElapsedMilliseconds + ms);
        }
    }
}

Nun, wenn ich es laufen, heißt es:

42ms

Über 100x schneller.

Frage

Was ist in der MakeAggregateGoFaster Namespace?

Update 2: Schrieb meine Antwort hier oben .

Veröffentlicht am 10/12/2008 um 00:12
quelle vom benutzer
In anderen Sprachen...                            


5 antworten

stimmen
3

Nun, das wäre hängt ganz von welchem ​​Code ist im MageAggregateGoFaster Namespace jetzt wäre es nicht?

Dieser Namespace ist nicht Teil der .NET-Laufzeit, so haben Sie in einigen benutzerdefinierten Code verknüpft.

Persönlich würde ich denken, dass etwas, das die String-Verkettung oder ähnlich erkennt, und eine Liste aufbaut, oder ähnliches, dann ein großes String ordnet und verwendet anhängen.

Eine schmutzige Lösung wäre:

namespace MakeAggregateGoFaster
{
    public static class Extensions
    {
        public static String Aggregate(this IEnumerable<String> source, Func<String, String, String> fn)
        {
            StringBuilder sb = new StringBuilder();
            foreach (String s in source)
            {
                if (sb.Length > 0)
                    sb.Append(", ");
                sb.Append(s);
            }

            return sb.ToString();
        }
    }
}

schmutzig, weil dieser Code, während das tun, was Sie sagen, Sie mit Ihrem Programm erleben, die Funktion Delegierten überhaupt nicht verwendet werden. Es wird jedoch bringt die Ausführungszeit von um 2800ms bis 11ms auf meinem Computer herunter, und immer noch die gleichen Ergebnisse erzielen.

Nun, das nächste Mal, vielleicht sollten Sie eine gute Frage stellen , anstatt nur sehen , wie klug ich bin Art von Brust-Schlagen?

Beantwortet am 10/12/2008 um 00:15
quelle vom benutzer

stimmen
5

Nicht die Frage zu beantworten, aber ich denke, die Standardmuster sind hier String oder string.Join zu verwenden:

string.join(", ",Enumerable.Range(0, size).Select(n => n.ToString()).ToArray())
Beantwortet am 10/12/2008 um 00:16
quelle vom benutzer

stimmen
15

Sie sind System.Linq.Aggregate mit Ihrer eigenen Erweiterungsmethode im Namensraum MakeAggregateGoFaster ‚zwingend‘.

Vielleicht spezialisiert auf IEnumerable<string>und die Verwendung eines Stringbuilder zu machen?

Vielleicht nimmt eine Expression<Func<string, string, string>>Stelle eines Func<string, string, string>so kann er den Ausdrucksbaum analysieren und einen Code zu kompilieren , die Stringbuilder statt dem Aufruf der Funktion direkt verwendet?

Einfach raten.

Beantwortet am 10/12/2008 um 00:30
quelle vom benutzer

stimmen
4

Der Grund, warum ich fragte, ob es ein Rätsel war, weil ein Puzzle ist erlaubt, so lange in unterschiedlichem Maße Robustheit zu opfern, wie sie den Brief der gestellten Aufgabe erfüllt. In diesem Sinne geht, hier:

Lösung 1 (läuft sofort, Problem lässt sich aber nicht):

public static string Aggregate(this IEnumerable<string> l, Func<string, string, string> f) {
     return "";
}

Lösung 2 (läuft etwa so schnell wie das Problem erfordert, aber ignoriert die Delegierten vollständig):

public static string Aggregate(this IEnumerable<string> l, Func<string, string, string> f) {
    StringBuilder sb = new StringBuilder();
    foreach (string item in l)
        sb.Append(", ").Append(item);
    return sb.Remove(0,2).ToString();
}
Beantwortet am 10/12/2008 um 00:35
quelle vom benutzer

stimmen
40

Warum nicht eine der anderen Formen der Aggregate verwenden?

Enumerable.Range(0, size ).Aggregate(new StringBuilder(),
        (a, b) => a.Append(", " + b.ToString()),
        (a) => a.Remove(0,2).ToString());

Sie können jede Art für Ihre Samen angeben, führen, was die Formatierung oder benutzerdefinierte Anrufe in der ersten Lambda-Funktion benötigt werden, und dann in der zweiten Lambda-Funktion den Ausgangstyp anpassen. Die in Funktionen, die bereits gebaut bieten die Flexibilität, die Sie benötigen. Meine Läufe ging von 1444ms bis 6 ms.

Beantwortet am 14/01/2009 um 18:18
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more