编程时几乎本能地决定何时使用for循环或foreach,但是选择使用Enumerable.Range的决定性因素或问题空间是什么?
当我们想要迭代设定次数(通过简单数据类型)来计算/执行重复任务时,选择 For Loop 。
For Each 类似,但在我们想要迭代复杂对象列表来计算/执行重复性任务时选择。
同样,使用Enumerable.Range的决定因素是什么?
IEnumerable<int> squares = Enumerable.Range(4, 3).Select(x => x * x);
答案 0 :(得分:10)
foreach
是关于现有集合/集合的迭代。
Enumerable.Range
用于生成集合/集合。一般来说,如果for
可以生成一个Enumerable.Range
循环只是为了生成一个集合,那么你只需要编写一个更长的样板代码并要求你分配一些首先填充的存储类型(例如List<int>
)。
答案 1 :(得分:5)
如上所述,Enumerable.Range不是针对循环,而是创建范围。这使得Linq中的一个衬里成为可能,而无需创建子集。
这种能力的另一个优点是,你甚至可以在子语句中生成一个子范围,这对于for
和lambda来说并不总是可能的,因为在lambdas中不可能产生。
例如,SelectMany
也可以使用Enumerable.Range。
测试集合:
class House
{
public string Name { get; set; }
public int Rooms;
}
var houses = new List<House>
{
new House{Name = "Condo", Rooms = 3},
new House{Name = "Villa", Rooms = 10}
};
这个例子本身并没有多大价值,但是为了获得所有房间,Linq的实现将是:
var roomsLinq = houses.SelectMany(h => Enumerable.Range(1, h.Rooms).Select(i => h.Name + ", room " + i));
通过迭代,它需要2次迭代:
var roomsIterate = new List<string>();
foreach (var h in houses)
{
for (int i = 1; i < h.Rooms + 1; i++)
{
roomsIterate.Add(h.Name + ", room " + i);
}
}
你仍然可以说,第二个代码更具可读性,但这归结为使用Linq或一般不使用。
因此,更进一步,我们想要所有房间的IEnumerable<IEnumerable<string>>
(每个房间可以容纳多个房间的字符串)。
的LINQ:
listrooms = houses.Select(h => Enumerable.Range(1, h.Rooms).Select(i => h.Name + ", room " + i));
但是现在,在使用迭代时我们需要2个集合:
var list = new List<IEnumerable<string>>();
foreach (var h in houses)
{
var rooms = new List<string>();
for (int i = 1; i < h.Rooms + 1; i++)
{
rooms.Add(h.Name + ", room " + i);
}
list.Add(rooms);
}
另一个场景,即Linqs和lambdas的优点之一是,您可以将它们用作参数(例如用于注入目的),这可以通过Enumerable以更简单的方式实现。范围。
例如,你有一个函数,它带有一个参数roomgenerator
static IEnumerable<Furniture> CreateFurniture(Func<House,IEnumerable<string>> roomgenerator){
//some house fetching code on which the roomgenerator is used, but only the first 4 rooms are used, so not the entire collection is used.
}
上面的房间迭代可以使用Enumerable.Range返回,但是通过迭代,必须首先创建房间的子集合,或者生成结果的单独函数。 子集合的缺点是它总是完全填充,即使枚举中只需要一个项目。单独的方法通常是矫枉过正的,因为它只需要单个参数使用,因此Enumerable.Range可以节省一天。
答案 2 :(得分:2)
Enumerable.Range()
是一个生成器,即它是一种生成某种n
项的简单而强大的方法。
需要一个具有相同类的随机数量实例的集合吗?没问题:
Enumerable.Range(1,_random.Next())
.Select(_ => new SomeClass
{
// Properties
});
答案 3 :(得分:1)
您可以将Enumerable.Range
视为一种回收集合子集的工具。
如果集合的内容是值类型,则还要创建每个集合的新实例。
是的,您可以使用for
循环,通过设置正确的迭代边界来实现,但是这样思考,几乎所有LINQ
都可以通过其他方式实现(最后它只是一个库) )。
但它具有简短,简洁和清晰的语法,这就是它如此广泛使用的原因。
答案 4 :(得分:1)
你的榜样已经足够好了。
我可以使用for循环构建结果
来执行相同的代码
基本上有两种方法可以使用循环构建它:
// building a collection for the numbers first
List<int> numbers = new List();
for (int i = 4; i < 7; i++)
numbers.Add(i);
IEnumerable<int> squares = numbers.Select(x => x * x);
// or building the result directly
List<int> squares = new List();
for (int i = 4; i < 7; i++)
numbers.Add(i * i);
两种解决方案的关键是你实际上需要创建一个你添加的集合。所以你在某个地方有一组数字。
但请查看Enumerable.Range
解决方案:Enumerable.Range
是生成器,它返回IEnumerable
,就像所有其他Linq方法一样,只创建迭代时的事情。所以从来没有一个包含所有数字的集合。