我的内存中有一个很大的List
,来自一个大约有20 properties
的类。
我想基于一个property
过滤此列表,对于特定任务,我只需要property
的列表。所以我的查询是这样的:
data.Select(x => x.field).Where(x => x == "desired value").ToList()
首先使用Select
或使用Where
,哪一个能让我获得更好的效果?
data.Where(x => x.field == "desired value").Select(x => x.field).ToList()
如果这与data type
我将数据保存在内存或字段类型中有关,请告诉我。请注意,我也需要这些对象用于其他任务,因此我无法在首先过滤它们并将它们加载到内存之前。
答案 0 :(得分:8)
使用Select先选或使用Where。
,哪一个给了我更好的表现
Where
第一种方法效率更高,因为它首先过滤您的收藏,然后仅对过滤的值执行Select
。
从数学角度讲,Where
- 第一种方法需要N + N'
次操作,其中N'
是属于Where
条件的收集项数。
因此,最少需要N + 0 = N
次操作(如果没有项目通过此Where
条件),最多需要N + N = 2 * N
次操作(如果所有项都通过了条件)。
与此同时,Select
第一种方法将始终采用精确的2 * N
操作,因为它遍历所有对象以获取属性,然后遍历所有对象以过滤它们。
我已完成基准测试以证明我的答案。
结果:
Condition value: 50
Where -> Select: 88 ms, 10500319 hits
Select -> Where: 137 ms, 20000000 hits
Condition value: 500
Where -> Select: 187 ms, 14999212 hits
Select -> Where: 238 ms, 20000000 hits
Condition value: 950
Where -> Select: 186 ms, 19500126 hits
Select -> Where: 402 ms, 20000000 hits
如果您多次运行基准测试,那么您会看到Where -> Select
方法点击次数不时变化,而Select -> Where
方法总是需要2N
次操作。
IDEOne演示:
代码:
class Point
{
public int X { get; set; }
public int Y { get; set; }
}
class Program
{
static void Main()
{
var random = new Random();
List<Point> points = Enumerable.Range(0, 10000000).Select(x => new Point { X = random.Next(1000), Y = random.Next(1000) }).ToList();
int conditionValue = 250;
Console.WriteLine($"Condition value: {conditionValue}");
Stopwatch sw = new Stopwatch();
sw.Start();
int hitCount1 = 0;
var points1 = points.Where(x =>
{
hitCount1++;
return x.X < conditionValue;
}).Select(x =>
{
hitCount1++;
return x.Y;
}).ToArray();
sw.Stop();
Console.WriteLine($"Where -> Select: {sw.ElapsedMilliseconds} ms, {hitCount1} hits");
sw.Restart();
int hitCount2 = 0;
var points2 = points.Select(x =>
{
hitCount2++;
return x.Y;
}).Where(x =>
{
hitCount2++;
return x < conditionValue;
}).ToArray();
sw.Stop();
Console.WriteLine($"Select -> Where: {sw.ElapsedMilliseconds} ms, {hitCount2} hits");
Console.ReadLine();
}
}
这些问题对您来说也很有趣。它们与Select
和Where
无关,但它们与LINQ订单效果有关:
Does the order of LINQ functions matter?
Order of LINQ extension methods does not affect performance?
答案 1 :(得分:5)
答案取决于你收藏的状态。
<强>更新强>
@YeldarKurmangaliyev用一个具体的例子和基准测试写了答案。我运行了类似的代码来验证他的声明,我们的结果正好相反,这是因为我运行了与他相同的测试,但是对象并不像他以前使用的Point
类型那么简单进行他的测试。
代码非常类似于他的代码,只是我将类的名称从Point
更改为EnumerableClass
。
下面给出了我曾经构成EnumerableClass
类的类:
public class EnumerableClass
{
public int X { get; set; }
public int Y { get; set; }
public String A { get; set; }
public String B { get; set; }
public String C { get; set; }
public String D { get; set; }
public String E { get; set; }
public Frame F { get; set; }
public Gatorade Gatorade { get; set; }
public Home Home { get; set; }
}
public class Home
{
private Home(int rooms, double bathrooms, Stove stove, InternetConnection internetConnection)
{
Rooms = rooms;
Bathrooms = (decimal) bathrooms;
StoveType = stove;
Internet = internetConnection;
}
public int Rooms { get; set; }
public decimal Bathrooms { get; set; }
public Stove StoveType { get; set; }
public InternetConnection Internet { get; set; }
public static Home GetUnitOfHome()
{
return new Home(5, 2.5, Stove.Gas, InternetConnection.Att);
}
}
public enum InternetConnection
{
Comcast = 0,
Verizon = 1,
Att = 2,
Google = 3
}
public enum Stove
{
Gas = 0,
Electric = 1,
Induction = 2
}
public class Gatorade
{
private Gatorade(int volume, Color liquidColor, int bottleSize)
{
Volume = volume;
LiquidColor = liquidColor;
BottleSize = bottleSize;
}
public int Volume { get; set; }
public Color LiquidColor { get; set; }
public int BottleSize { get; set; }
public static Gatorade GetGatoradeBottle()
{
return new Gatorade(100, Color.Orange, 150);
}
}
public class Frame
{
public int X { get; set; }
public int Y { get; set; }
private Frame(int x, int y)
{
X = x;
Y = y;
}
public static Frame GetFrame()
{
return new Frame(5, 10);
}
}
类Frame
,Gatorade
和Home
各有一个静态方法,可以返回其类型的实例。
以下是主要计划:
public static class Program
{
const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static readonly Random Random = new Random();
private static string RandomString(int length)
{
return new string(Enumerable.Repeat(Chars, length)
.Select(s => s[Random.Next(s.Length)]).ToArray());
}
private static void Main()
{
var random = new Random();
var largeCollection =
Enumerable.Range(0, 1000000)
.Select(
x =>
new EnumerableClass
{
A = RandomString(500),
B = RandomString(1000),
C = RandomString(100),
D = RandomString(256),
E = RandomString(1024),
F = Frame.GetFrame(),
Gatorade = Gatorade.GetGatoradeBottle(),
Home = Home.GetUnitOfHome(),
X = random.Next(1000),
Y = random.Next(1000)
})
.ToList();
const int conditionValue = 250;
Console.WriteLine(@"Condition value: {0}", conditionValue);
var sw = new Stopwatch();
sw.Start();
var firstWhere = largeCollection
.Where(x => x.Y < conditionValue)
.Select(x => x.Y)
.ToArray();
sw.Stop();
Console.WriteLine(@"Where -> Select: {0} ms", sw.ElapsedMilliseconds);
sw.Restart();
var firstSelect = largeCollection
.Select(x => x.Y)
.Where(y => y < conditionValue)
.ToArray();
sw.Stop();
Console.WriteLine(@"Select -> Where: {0} ms", sw.ElapsedMilliseconds);
Console.ReadLine();
Console.WriteLine();
Console.WriteLine(@"First Where's first item: {0}", firstWhere.FirstOrDefault());
Console.WriteLine(@"First Select's first item: {0}", firstSelect.FirstOrDefault());
Console.WriteLine();
Console.ReadLine();
}
}
<强>结果:强>
我多次运行测试并发现
.Select()。其中() 的效果优于 .Where()。选择()。
当集合大小为1000000时。
以下是我将每个
EnumerableClass
对象的Y
值强制为5的第一个测试结果,因此每个项目都通过了 Where :
Condition value: 250
Where -> Select: 149 ms
Select -> Where: 115 ms
First Where's first item: 5
First Select's first item: 5
以下是第二个测试结果,其中我强制每个
EnumerableClass
对象的Y
值为251,因此没有项目通过 Where :
Condition value: 250
Where -> Select: 110 ms
Select -> Where: 100 ms
First Where's first item: 0
First Select's first item: 0
显然,结果非常依赖于 的状态
该集合的州,我一再提及包括:
对答案评论的回应:
此外,@ Enigmativity表示提前了解 Where 的结果,以便知道是先放 Where 还是先选择是一个Catch-22。从理论上和理论上来说,他是正确的,并不奇怪,这种情况可以在计算机科学的另一个领域看到 - Scheduling。
最佳调度算法是Shortest Job First,我们首先安排该作业将在最短时间内执行。但是,怎么会有人知道特定工作需要多长时间才能完成?嗯,答案是:
接下来的最短作业用于可以准确估算运行时间的专业环境。
因此,正如我在顶部所说(这也是我的答案的第一个,更短的版本),这个问题的正确答案将取决于当前的集合状态。 / p>
一般来说,
然后,在此答案顶部提到的指南对您有用。