簡體   English   中英

我怎么知道我是否正在迭代集合的最后一項?

[英]How do I know if I'm iterating on the last item of the collection?

我想在我正在迭代的Dictionary的最后一個KeyValuePair上做一些不同的事情。

For Each item In collection
    If ItsTheLastItem
        DoX()
    Else
        DoY()
    End If
Next 

這可能嗎?

重新編輯:我沒有使用字典值,我實際上使用的是KeyValuePair列表。 我轉換了它們,后來沒有注意到,愚蠢的我。

除非您想自己實現foreach ,否則請使用計數器(C#代碼):

int count = collection.Count;
int counter = 0;

foreach(var item in collection)
{
  counter++;
  if(counter == count)
    DoX();
  else
    DoY();
}

請注意,這只適用於非流式IEnumerable<T> ,同樣,根據實現, Count會導致集合走兩次。

我會制作你自己的擴展方法。 這里的實現保證您只需走一次集合。

static class IEnumerableExtensions {
    public static void ForEachExceptTheLast<T>(
        this IEnumerable<T> source,
        Action<T> usualAction,
        Action<T> lastAction
    ) {
        var e = source.GetEnumerator();
        T penultimate;
        T last;
        if (e.MoveNext()) {
            last = e.Current;
            while(e.MoveNext()) {
                penultimate = last;
                last = e.Current;
                usualAction(penultimate);
            }
            lastAction(last);
        }
    }
}    

用法:

Enumerable.Range(1, 5)
          .ForEachExceptTheLast(
              x => Console.WriteLine("Not last: " + x),
              x => Console.WriteLine("Last: " + x)
);

輸出:

Not last: 1
Not last: 2
Not last: 3
Not last: 4
Last: 5

為什么不使用:

List<string> list = new List<string>();
// add items

foreach (string text in list)
{
    if (text.Equals(list[list.Count - 1]))
    {
        // last item
    }
    else
    {
        // not last item
    }
}

將集合轉換為列表(如LINQ的ToList())並使用for(int i = 0)...循環進行迭代。

你不能用IEnumerable<T>自然地做到這一點,因為在你試圖進入下一個元素之前你不會知道是否還有其他元素。

但是,在我的MiscUtil庫中,我有一個名為SmartEnumerable東西,它預先讀取一個項目,以便提供以下屬性:

  • IsFirst
  • IsLast
  • Index
  • Value

有關使用說明,請參閱此頁面 例如:

For Each item In collection.ToSmartEnumerable()
    If item.IsFirst
        DoX()
    Else
        DoY()
    End If
Next 

您需要使用item.Value來獲取當前項的值。

關於迭代字典的一點是 - 它們實際上並不是任何順序。 因此,雖然您可以迭代並且有第一個條目和最后一個條目,但您不應該假設它們將是添加的第一個條目和分別添加的最后一個條目。 對於您的用例而言,這可能不是問題,但您應該意識到這一點。

我只是有一個不使用計數器的想法。

For Each item In collection.GetRange(0, collection.Count - 1)
    DoY(item)
Next
DoX(collection.Last)

編輯:對不起,這是一個List,我之前已經轉換過它,intellisense給了我List方法而不是Dictionary方法。

我根據上面的@CamiloMartin答案創建了一個從4個八位字節構建IP字符串的解決方案。

 String sIP;
 StringBuilder sb = new StringBuilder();
 List<String> lstOctets= new List<string>{ usrIP1.Text, usrIP2.Text, usrIP3.Text, usrIP4.Text };
 foreach (String Octet in lstOctets.GetRange(0,lstOctets.Count - 1))
 {
    sb.Append(string.Format("{0:d}.", Octet));
 }
 if (lstOctets.Count == 4)
    sb.Append(string.Format("{0:d}", lstOctets[lstOctets.Count - 1]));
 else
     sb.Append(string.Format("{0:d}.0", lstOctets[lstOctets.Count - 1]));
 sIP = sb.ToString();
        foreach (var item in collection.Reverse().Skip(1))
        {

        }
        // do here the stuff related to list.LastOrDefaut()

另一種方法是維護迭代索引,當命中collection.Length-2collection.Count()-2然后停止循環並使用最后一個元素執行任何操作。

但正如@BrokenGlass所說,要注意它可能對你的應用程序產生的副作用。

一般來說,你必須特別小心使用Linq。 例如每次你在LINQ to SQL的訪問集合的時候,你再執行查詢,所以更好的做法是通過簡單地調用一次急切地運行它.ToList()和使用,在內存中的集合,只要你想盡可能多。

使用詞典,您有多種選擇

Dim dictionary as new Dictionary(of String, MyObject)
For Each item in dictionary
    // item is KeyValue pair
Next

For Each item in dictionary.Keys
    // item is String
Next

For Each item in dictionary.Keys
    // item is MyObject
Next

我建議你對ValueCollection進行itterate並使用一個計數器或在當前和最后一項之間進行Equals比較(這可能會慢一點,但你保存一個計數器變量;)不要忘記添加一個空的檢查名單。

For Each item in dictionary.Values

    If dictionary.Count > 0 AndAlso _
        item.Equals(dictionary.Values(dictionary.Count - 1)) Then
        Console.WriteLine("Last Item")
    Else
        Console.WriteLine("Some other Item")
    End If

Next

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM