Для более быстрого и повторного использования я бы использовал традиционное «для».
Edited
Я написал код тестирования с учетом:
- списки с 1000 случайных целых чисел.
- 200 тестов на каждый метод.
- 1, 2, 4 и 8 использует результат, чтобы показать необходимость преобразования
IEnumerable<int>
результата LINQ в лучшую структуру данных, например List<int>
, если вы используете результат много раз.
Результат таков:
1 uses per result
Tigrou-Where : count= 93, 3.167,0ms
Tigrou-Intersect : count= 89, 116,0ms
Tigrou-Join : count= 96, 179,0ms
Servy-GroupJoin : count= 93, 262,0ms
Servy-HashSet : count= 93, 71,0ms
Servy-JoinDisctinct : count= 93, 212,0ms
JoseH-TheOldFor : count= 93, 72,0ms
2 uses per result
Tigrou-Where : count= 93, 6.007,0ms
Tigrou-Intersect : count= 89, 182,0ms
Tigrou-Join : count= 96, 293,0ms
Servy-GroupJoin : count= 93, 455,0ms
Servy-HashSet : count= 93, 99,0ms
Servy-JoinDisctinct : count= 93, 407,0ms
JoseH-TheOldFor : count= 93, 73,0ms
4 uses per result
Tigrou-Where : count= 93, 11.866,0ms
Tigrou-Intersect : count= 89, 353,0ms
Tigrou-Join : count= 96, 565,0ms
Servy-GroupJoin : count= 93, 899,0ms
Servy-HashSet : count= 93, 165,0ms
Servy-JoinDisctinct : count= 93, 786,0ms
JoseH-TheOldFor : count= 93, 73,0ms
8 uses per result
Tigrou-Where : count= 93, 23.831,0ms
Tigrou-Intersect : count= 89, 724,0ms
Tigrou-Join : count= 96, 1.151,0ms
Servy-GroupJoin : count= 93, 1.807,0ms
Servy-HashSet : count= 93, 299,0ms
Servy-JoinDisctinct : count= 93, 1.570,0ms
JoseH-TheOldFor : count= 93, 81,0ms
И код:
class Program
{
static void Main(string[] args)
{
Random random = new Random(Environment.TickCount);
var cases = 1000;
List<int> a = new List<int>(cases);
List<int> b = new List<int>(cases);
for (int c = 0; c < cases; c++)
{
a.Add(random.Next(9999));
b.Add(random.Next(9999));
}
var times = 100;
var usesCount = 1;
Console.WriteLine("{0} times", times);
for (int u = 0; u < 4; u++)
{
Console.WriteLine();
Console.WriteLine("{0} uses per result", usesCount);
TestMethod(a, b, "Tigrou-Where", Where, times, usesCount);
TestMethod(a, b, "Tigrou-Intersect", Intersect, times, usesCount);
TestMethod(a, b, "Tigrou-Join", Join, times, usesCount);
TestMethod(a, b, "Servy-GroupJoin", GroupJoin, times, usesCount);
TestMethod(a, b, "Servy-HashSet", HashSet, times, usesCount);
TestMethod(a, b, "Servy-JoinDisctinct", JoinDistinct, times, usesCount);
TestMethod(a, b, "JoseH-TheOldFor", TheOldFor, times, usesCount);
usesCount *= 2;
}
Console.ReadLine();
}
private static void TestMethod(List<int> a, List<int> b, string name, Func<List<int>, List<int>, IEnumerable<int>> method, int times, int usesCount)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
int count = 0;
for (int t = 0; t < times; t++)
{
// Process
var result = method(a, b);
// Count
for (int u = 0; u < usesCount; u++)
{
count = 0;
foreach (var item in result)
{
count++;
}
}
}
stopwatch.Stop();
Console.WriteLine("{0,-20}: count={1,4}, {2,8:N1}ms",
name, count, stopwatch.ElapsedMilliseconds);
}
private static IEnumerable<int> Where(List<int> a, List<int> b)
{
return a.Where(x => b.Contains(x));
}
private static IEnumerable<int> Intersect(List<int> a, List<int> b)
{
return a.Intersect(b);
}
private static IEnumerable<int> Join(List<int> a, List<int> b)
{
return a.Join(b, x => x, y => y, (x, y) => x);
}
private static IEnumerable<int> GroupJoin(List<int> a, List<int> b)
{
return from n in a
join k in b
on n equals k into matches
where matches.Any()
select n;
}
private static IEnumerable<int> HashSet(List<int> a, List<int> b)
{
var set = new HashSet<int>(b);
return a.Where(n => set.Contains(n));
}
private static IEnumerable<int> JoinDistinct(List<int> a, List<int> b)
{
return a.Join(b.Distinct(), x => x, y => y, (x, y) => x);
}
private static IEnumerable<int> TheOldFor(List<int> a, List<int> b)
{
var result = new List<int>();
int countA = a.Count;
var setB = new HashSet<int>(b);
for (int loopA = 0; loopA < countA; loopA++)
{
var itemA = a[loopA];
if (setB.Contains(itemA))
result.Add(itemA);
}
return result;
}
}
Изменение строки в коде, чтобы преобразовать результат в List<int>
перед использованием его бросили их на 8 использований:
8 uses per result
Tigrou-Where : count= 97, 2.974,0ms
Tigrou-Intersect : count= 91, 91,0ms
Tigrou-Join : count= 105, 150,0ms
Servy-GroupJoin : count= 97, 224,0ms
Servy-HashSet : count= 97, 74,0ms
Servy-JoinDisctinct : count= 97, 223,0ms
JoseH-TheOldFor : count= 97, 75,0ms
Итак, я думаю, что победитель : Метод Servy-HashSet с небольшим количеством варианта:
var set = new HashSet<int>(b);
var result = a.Where(n => set.Contains(n)).ToList();
'a.Where (х => b.Contains (а))', вероятно, следует 'a.Where (х => b.Contains (х)) ' – sloth
К сожалению, это всегда будет медленным в' List ', потому что' Contains' является операцией O (n). Вы можете попробовать «HashSet », но следует предупредить, что для того, чтобы быть быстрым, вам нужно переопределить «GetHashCode» и «Equals» для типа 'T' (при условии, что' T' является некадровым типом) –
Mgetz
@Mgetz, это это то, что я предложил в последней части, используя «Словарь». Но вы правы, достаточно использовать «HashSet». – tigrou