如何在最后一次迭代期间退出foreach循环?

4
foreach (Item i in Items)

 {
      do something with i;
      do another thing with i (but not if last item in collection);
 }

2
有时候你可以重新表述这个问题,使其更易处理。这是我写的一篇关于上次有人问我这个问题的文章:http://blogs.msdn.com/ericlippert/archive/2009/04/13/restating-the-problem.aspx - Eric Lippert
感谢您写得如此好的文章,但虽然我不是高级程序员,但我仍然想知道如何确定最后一个项目,而不管实际目的是什么。我认为这个问题比我的其他混淆问题更清晰。 - zsharp
9个回答

24

最好使用for循环:

int itemCount = Items.Count;
for (int i = 0; i < itemCount; i++)
{
    var item = Items[i];

    // do something with item

    if (i != itemCount - 1)
    {
        // do another thing with item
    } 
}

+1,不过这只适用于Items集合有索引的情况。 - Jon Seigel
1
如果集合没有索引,最后一项的概念是没有意义的。 - Jon Seigel
1
@Jon:一点也不。IEnumerable<T>本质上是有序的但没有索引。 - Jon Skeet
1
(或许更准确地说,它本质上是有序的,但没有通过索引进行随机访问,也不会提供计数。) - Jon Skeet
谢谢您的回答,但我必须把它交给Jon Skeet,因为他的解决方案仍然使用foreach,这很有效。 - zsharp

10

我在这里使用MiscUtil中的帮助类来实现此功能。下面是示例代码(来自第一个链接):

foreach (SmartEnumerable<string>.Entry entry in
         new SmartEnumerable<string>(list))
{
    Console.WriteLine ("{0,-7} {1} ({2}) {3}",
                       entry.IsLast  ? "Last ->" : "",
                       entry.Value,
                       entry.Index,
                       entry.IsFirst ? "<- First" : "");
}

如果您使用的是.NET 3.5和C# 3,则可以使用扩展方法和隐式类型,这样会更简单:

foreach (var entry in list.AsSmartEnumerable())
{
    Console.WriteLine ("{0,-7} {1} ({2}) {3}",
                       entry.IsLast  ? "Last ->" : "",
                       entry.Value,
                       entry.Index,
                       entry.IsFirst ? "<- First" : "");
}

与使用 for 循环相比,这种方法的好处在于它适用于 IEnumerable<T> 而不是 IList<T>,因此可以与 LINQ 等一起使用而无需缓冲所有内容。(请注意,它在内部维护单个条目的缓冲区。)


很好。以前看过你的MiscUtil库,但是里面的内容太多了,有点不知所措。我相信还有很多像这样的好东西。如果我有时间去看的话就好了。 :) - Matt Lacey
通常为了在项之间输出某种分隔符或类似的内容,这正是我的问题。 - zsharp
1
这有点杂乱无章,是的。在某个时候,我应该将其分离出来,或者至少将其移动到code.google.com上。只是找时间的问题...好的一面是,我实现它的方式是你通常只需要抓取一个或两个类而不是整个库。 - Jon Skeet
@zsharp,你真的应该说明一下你想做什么:你可以使用string.Join()来实现! - tster

4
foreach (Item i in Items.Take(Items.Count - 1))
{
      do something with i;
      do another thing with i (but not if last item in collection);
}

1
这个不行,因为它没有对最后一个项目执行第一次操作。 - Ben M
1
是的,在循环最后一个项目后,第一次操作应该被重复执行。 - Kamarey

2

使用for循环代替foreach怎么样?

for (int i = 0; i < Items.Count; i++) {
    //do something with i;
    if (i == Items.Count - 1) {
        //do another thing with Items[Items.count - 1];
    }
}

2

如果你使用C#-3.0,你可以使用LINQ:

    foreach (Item i in items.Take(Items.Count - 1))
    {
...
    }

2

正如Jon Siegel所指出的:

如果集合没有索引,那么最后一个项目的概念当然是没有意义的。

话虽如此,假设您想对 IEnumerable<T> 中除最后一个任意访问的枚举器之外的每个项目执行某些操作。 那就好办了:

IEnumerator<Item> e = Items.GetEnumerator();
e.MoveNext();

while (e.Current != null)
{
    Item i = e.Current;
    // do something with i;

    if e.MoveNext()
    {
        // do another thing with i
    }
}

1

看起来这就是你想要解决的问题。

List<string> list = getList();
string.Join(", ", list.ToArray());

0

我写这个可能会让我感觉很不舒服,但它可能会解决你的问题。

Item last = null;

foreach (Item i in Items)
{
      last = i;
}

foreach (Item i in Items)
 {
      do something with i;

      if (i!=last){
            do another thing with i (but not if last item in collection);
      }
 }

不是最佳方式:在这里,您再一次循环遍历Items集合,如果某个项具有Equals方法中的一些复杂逻辑,则会影响性能(这行代码:“if(i!=last){”)。 - Kamarey
1
@Kamarey:这是一个很好的解释,为什么你应该“感觉写这个很肮脏”。 - Greg

0

您可以在按钮单击事件中按照这个逻辑进行操作。

namespace LastEnumItem
{
    public partial class Form1 : Form
    {
        List<string> lst = new List<string>(); 
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            for(int i=0; i<=10 ; i++)
            {
                lst.Add("string " + i.ToString());
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string lastitem = lst[lst.Count-1];
            foreach (string str in lst)
            {
                if (lastitem != str)
                {
                    // do something
                }
                else
                {
                    MessageBox.Show("Last Item :" + str);
                }
            }
        }


    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接