Orens Antwort weist einen Fehler bei der Verwendung der Stoppuhr auf. Es wird am Ende der Schleife nicht zurückgesetzt, nachdem die Zeit Any()
gemessen wurde.
Hinweis, wie es zu Beginn der Schleife geht zurück mit der Stoppuhr nie Reset()
so zu sein, dass die Zeit, den intersect
hinzugefügt wird umfasst die von Any()
Zeit genommen.
Folgendes ist eine korrigierte Version.
Ein Release-Build außerhalb jeden Debugger gibt dieses Ergebnis auf meinem PC laufen:
Intersect: 1ms
Any: 6743ms
Hinweis, wie ich für diesen Test zwei nicht überlappende Stringlisten zu machen. Beachten Sie auch, dass dies ein Worst-Case-Test ist.
Wo viele Schnittpunkte (oder Schnittpunkte, die in der Nähe des Anfanges der Daten auftreten) auftreten, ist Oren ganz richtig zu sagen, dass Any()
schneller sein sollte. Wenn die echten Daten normalerweise Kreuzungen enthalten, ist es wahrscheinlich besser, Any()
zu verwenden. Andernfalls verwenden Sie Intersect()
. Es ist sehr datenabhängig.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Demo
{
class Program
{
void run()
{
double intersect = 0;
double any = 0;
Stopwatch stopWatch = new Stopwatch();
List<string> L1 = Enumerable.Range(0, 10000).Select(x => x.ToString()).ToList();
List<string> L2 = Enumerable.Range(10000, 10000).Select(x => x.ToString()).ToList();
for (int i = 0; i < 10; i++)
{
stopWatch.Restart();
Intersect(L1, L2);
stopWatch.Stop();
intersect += stopWatch.ElapsedMilliseconds;
stopWatch.Restart();
Any(L1, L2);
stopWatch.Stop();
any += stopWatch.ElapsedMilliseconds;
}
Console.WriteLine("Intersect: " + intersect + "ms");
Console.WriteLine("Any: " + any + "ms");
}
private static bool Any(List<string> lst1, List<string> lst2)
{
return lst1.Any(lst2.Contains);
}
private static bool Intersect(List<string> lst1, List<string> lst2)
{
return lst1.Intersect(lst2).Any();
}
static void Main()
{
new Program().run();
}
}
}
Zu Vergleichszwecken schrieb ich meine eigenen Test int
Sequenzen zu vergleichen:
intersect took 00:00:00.0065928
any took 00:00:08.6706195
Der Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Demo
{
class Program
{
void run()
{
var lst1 = Enumerable.Range(0, 10000);
var lst2 = Enumerable.Range(10000, 10000);
int count = 10;
DemoUtil.Time(() => lst1.Intersect(lst2).Any(), "intersect", count);
DemoUtil.Time(() => lst1.Any(lst2.Contains), "any", count);
}
static void Main()
{
new Program().run();
}
}
static class DemoUtil
{
public static void Print(this object self)
{
Console.WriteLine(self);
}
public static void Print(this string self)
{
Console.WriteLine(self);
}
public static void Print<T>(this IEnumerable<T> self)
{
foreach (var item in self)
Console.WriteLine(item);
}
public static void Time(Action action, string title, int count)
{
var sw = Stopwatch.StartNew();
for (int i = 0; i < count; ++i)
action();
(title + " took " + sw.Elapsed).Print();
}
}
}
Wenn ich auch Zeit, dies für überlappende Bereiche durch Änderung der Listen dazu und die count
zu 10000:
var lst1 = Enumerable.Range(10000, 10000);
var lst2 = Enumerable.Range(10000, 10000);
ich diese Ergebnisse:
intersect took 00:00:03.2607476
any took 00:00:00.0019170
In diesem Fall Any()
eindeutig viel schneller ist.
Fazit
Die Worst-Case-Leistung ist sehr schlecht für Any()
aber acceptible für Intersect()
. Die Best-Case-Leistung ist sehr gut für Any()
und schlecht für Intersect()
. (und am besten Fall für Any()
ist wahrscheinlich Worst-Case für Intersect()
!)
Der Any()
Ansatz ist O (N^2) im schlimmsten Fall und O (1) im besten Fall. Der Intersect()
Ansatz ist immer O (N) (da es Hashing verwendet, nicht sortiert wird, sonst wäre es O (N (Log (N)))
Sie auch die Speichernutzung berücksichtigen müssen. Die Intersect()
Methode Bedürfnisse eine Kopie von einem der Eingänge zu nehmen, während Any()
nicht.
Deshalb ist die beste Entscheidung zu treffen, die Sie wirklich brauchen die Eigenschaften der realen Daten kennen, und Tests tatsächlich durchführen.
Wenn Sie wirklich Ich möchte nicht, dass Any()
im schlimmsten Fall zu einem O (N^2) wird, dann solltest du Intersect()
verwenden e dass Sie am besten mit Any()
arbeiten.
Und natürlich spielt die meiste Zeit keine Rolle!
Wenn Sie diesen Teil des Codes nicht als Engpass erkannt haben, ist dies nur von akademischem Interesse. Sie sollten Ihre Zeit mit dieser Art von Analyse nicht verschwenden, wenn es kein Problem gibt. :)
Führen Sie einige Tests durch, oder sehen Sie sich die erzeugte IL an? – zimdanen
Von http://ericlippert.com/2012/12/17/performance-rant/ _Wenn du zwei Pferde hast und du wissen willst, welche der beiden die schnellere ist, ** renne deine Pferde ** ._ –
Wenn eins ist deutlich besser oder schlechter als die andere, dann wäre die Frage nach dem Warum gültig. Aber ohne etwas über Ihre Daten zu wissen, ist es unmöglich zu antworten. – Bobson