有没有比 count++ 更优雅的方式来处理 foreach 枚举中的第一个和最后一个项目?
在迭代 foreach 循环时,是否有比增加单独的计数器并每次检查它更优雅的方法来对第一个和最后一个项目进行操作?
例如,以下代码输出:
>>> [line1], [line2], [line3], [line4] <<<
这需要知道您何时对第一个和最后一个项目进行操作。现在在 C# 3 / C# 4 中是否有更优雅的方法来做到这一点?看来我可以使用 .Last() 或 .First() 或类似的东西。
using System;
using System.Collections.Generic;
using System.Text;
namespace TestForNext29343
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
List<string> lines = new List<string>
{
"line1",
"line2",
"line3",
"line4"
};
int index = 0;
foreach (var line in lines)
{
if (index == 0)
sb.Append(">>> ");
sb.Append("[" + line + "]");
if (index < lines.Count - 1)
sb.Append(", ");
else
sb.Append(" <<<");
index++;
}
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
}
}
Is there a more elegant way to act on the first and last items when iterating through a foreach loop than incrementing a separate counter and checking it each time?
For instance, the following code outputs:
>>> [line1], [line2], [line3], [line4] <<<
which requires knowing when you are acting on the first and last item. Is there a more elegant way to do this now in C# 3 / C# 4? It seems like I could use .Last() or .First() or something like that.
using System;
using System.Collections.Generic;
using System.Text;
namespace TestForNext29343
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
List<string> lines = new List<string>
{
"line1",
"line2",
"line3",
"line4"
};
int index = 0;
foreach (var line in lines)
{
if (index == 0)
sb.Append(">>> ");
sb.Append("[" + line + "]");
if (index < lines.Count - 1)
sb.Append(", ");
else
sb.Append(" <<<");
index++;
}
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
您当前的示例无需迭代即可完成。
如果您只是进行迭代,我发现将其替换为常规 for 循环并检查边界会更容易。
它比使用 .First() 和 .Last() 扩展方法要快得多。此外,如果列表中有两个项目具有相同(字符串)值,则与“最后一个”或“第一个”相比将不起作用。
Your current example can be done without iterating.
If you're just iterating I find it easier to just replace it with a regular for loop and check the boundaries.
It'll be a lot faster than using the .First() and .Last() extension methods. Besides, if you have two items in your list with the same (string) value comparing to Last or First won't work.
对于当您只有
IEnumerable
时如何以不同方式处理第一个和最后一个情况的一般问题,可以执行此操作的一种方法是直接使用枚举器:For the general question of how to handle First and Last cases differently when you only have an
IEnumerable<T>
, one way you can do this is by using the enumerator directly:不回答你的问题,但为了你的目的,我会使用
Not answering your question but for your purpose I would use
尝试以下代码。
以下是
ForEachHelper
类的代码。Try the following code.
Here is the code for the
ForEachHelper
class.我通常采用这种方法,在循环之前处理一个边界,然后在循环内处理另一个边界。而且我也喜欢递减而不是递增。我认为这主要是用户的偏好...
I usually take this approach, handle one boundary before the loop, then handle the other inside the loop. And i also like decrementing instead of incrementing. I think it is mostly user preference though...
我建议将
>>>
和<<<
放在循环之外。您还可以使用 String.Join 而不是 foreach 循环。
I would recommend putting your
>>>
and<<<
outside of the loop.You could also use a String.Join instead of a foreach loop.
可能有一种更“优雅”的使用
First
和Last
对其进行编码的方式,但效率低下使其不值得。我为
IEnumerable
编写了自己的Join
运算符(来自 Nito.KitchenSink)。它是完全可重用的(在.NET 3.5或4.0中):There may be a more "elegant" way of coding it using
First
andLast
, but the inefficiency makes it not worth it.I coded up my own
Join
operator forIEnumerable<string>
s (from Nito.KitchenSink). It's fully reusable (in .NET 3.5 or 4.0):您可以执行以下操作:
我知道这不能回答您的问题,但它可以解决您的问题......
You could do the following:
I know this does not answer your question but it solves your problem...
如果 StringBuilder 不为空,为什么不直接在 foreach 循环末尾追加呢?
Why not just append at the end of the
foreach
loop if the StringBuilder isn't empty?我的 C# 有点生疏,但应该是这样的:
从循环中排除第一项要容易得多(通过启动索引
在一个)而不是排除最后一个。我从 Eric Lippert 的博客中得到了这个想法
前一段时间,但我现在无法找到该帖子......
My C# is a bit rusty, but it should be something like:
It's much easier to exclude the first item from the loop (by starting the index
at one) than it is to exclude the last. I got this idea from Eric Lippert's blog
some time ago but I can't for the life of me find the post at the moment....
List 在内部使用数组来存储项目(称为 _items),因此lines[i] 本质上与访问数组成员一样快。 Enumerable.First() 和 Enumerable.Last() 使用列表的索引器访问列表的第一个和最后一个成员,因此lines.First()本质上是lines[0],lines.Last本质上是lines[lines.Count-1 ],加上一些范围检查。
这意味着 line==lines.First() 的成本相当于数组成员引用加上引用比较。除非您执行大量迭代,否则这不会打扰您。
如果你需要更快的东西,你可以使用 LinkedList。在这种情况下,First() 和 Last() 直接返回第一个和最后一个项目,但这似乎有点矫枉过正。
List uses an array internally to store items (called _items), so lines[i] is essentially as fast as accessing an array member. Enumerable.First() and Enumerable.Last() access the first and last members of the List using the Lists's indexer, so lines.First() is essentially lines[0] and lines.Last is essentially lines[lines.Count-1], plus some range checking.
What this means is that the cost of line==lines.First() amounts to an array member reference plus a reference comparison. Unless you perform a LOT of iterations, this shouldn't bother you.
If you need something faster you can use a LinkedList. In this case First() and Last() return the first and last items directly, but that seems like overkill.