【问题标题】:How to verify in a foreach loop whether the element is last in the collection?如何在 foreach 循环中验证元素是否在集合中的最后一个?
【发布时间】:2013-04-15 05:19:54
【问题描述】:

我有一个 foreach 循环,我需要在其中验证元素是否在我正在迭代的集合中的最后一个。我试过的:

foreach (var character in list) // list is of type `string` 
{
    if (character == list.Last())
    {

    }
}

但在这种情况下,如果我有"la la la"if 语句将在第二个字符上执行。

问题:如何编写if 语句以便在访问序列的最后一个元素时执行?

【问题讨论】:

  • 那么“la la la”是一个字符串吗? list 是什么?
  • 然后用繁体的for作为回答
  • 你为什么要这样做?您是想对除最后一个元素之外的所有元素执行操作,还是只更新最后一个元素?
  • @AlekseiChepovoi 也许这有点XY Problem。我假设您根据逗号之类的字符拆分字符串,然后将每个子字符串传递给可以确定类型的东西?需要识别最后一项是因为需要关闭最终类型?
  • @AlekseiChepovoi 你能不能不做类似"1,2,3,4".Split(',').Select(eachString => ToInt(eachString)).ToList() 的事情?这将避免很多其他的跑腿工作。

标签: c# if-statement foreach


【解决方案1】:

我建议使用索引而不是对象引用进行迭代,即

for (int i = 0; i <= list.Count-1; i++)
{
    if (i == list.Count-1)
    {
        // so something special with last item
    }
}

【讨论】:

  • 还是只处理循环内除最后一个以外的所有内容,并在循环外处理最后一个?
  • @RogerRowland 也是如此,但是,将其作为一般迭代的一部分进行意味着您可以一口气完成所有操作。 OP还特别询问了如何在inside循环中进行操作。
  • 为什么要迭代,没有它也可以轻松完成,看我的回答
  • @MareInfinitus 是的,当您不需要处理列表中的其他项目时,这一切都很好...... OP 说“我需要验证该元素是集合中的最后一个我正在迭代”。
  • @MareInfinitus 除了@James 所说的,如果您事先不知道列表中的最后一个字符怎么办?我怀疑.Last() 无论如何都会以与此解决方案相同的方式在内部进行枚举..
【解决方案2】:
foreach (var character in list) // list is of type `string` 
{
    if (character == list[list.Count - 1])
    {

    }
}

这是DEMO

作为替代方案,由于List实现了IEnumerable接口,您可以使用Enumerable.Last方法

返回序列的最后一个元素。

foreach (var character in list) // list is of type `string` 
{
    if (character == list.Last())
    {

    }
}

这是DEMO

【讨论】:

  • 我需要验证当前字符是否是序列中的最后一个字符,但是这个“if”验证当前字符是否等于最后一个字符
  • @AlekseiChepovoi 我不明白你的评论。你的意思是你检查当前的char List的最后一个char吗?
【解决方案3】:

由于您的列表实际上是一个字符串,因此您需要将其转换为列表。

var elementList = list.Split(" ");

然后您可以找到最后一个元素。

var lastElement = elementList.LastOrDefault();

只需检查使用 IsNullOrEmpty 处理空列表的情况。

【讨论】:

    【解决方案4】:

    如果您只想对最后一个字符执行操作,那么 Mare Infinitus' 代码应该可以解决问题。

    怎么样:

    var elementList = list.Split(" ");
    if (elementList.Last().Equals(character))
    {
       // do something here
    }
    

    应该可以,不需要foreach。

    但是,如果您想循环并对最后一个字符执行特定操作,则可以使用标准的for 循环。 James'答案:

    for (int i = 0; i <= list.Count-1; i++)
    {
        if (i == list.Count-1)
        {
            // so something special with last item
        }
    }
    

    【讨论】:

      【解决方案5】:

      如果你发现自己经常做这种事情,你可以使用扩展方法,让你询问序列中的元素是否是最后一项。

      这最初是由 Jon Skeet 写的; he called it "Smart Enumerable",我相信它是 MoreLinq Linq Extensions 的一部分(也是 Jon Skeet)。

      如果您确实使用了这样的东西,您的代码将如下所示:

      foreach (var character in list.AsSmartEnumerable()) 
          if (character.IsLast)
              // Do something with character.Value
      

      这是 Jon Skeet 实现的稍作修改的副本:

      /// <summary>
      /// Static class to make creation easier. If possible though, use the extension
      /// method in SmartEnumerableExt.
      /// </summary>
      
      public static class SmartEnumerable
      {
          /// <summary> method to make life easier.</summary>
          /// <typeparam name="T">Type of enumerable</typeparam>
          /// <param name="source">Source enumerable</param>
          /// <returns>A new SmartEnumerable of the appropriate type</returns>
      
          public static SmartEnumerable<T> Create<T>(IEnumerable<T> source)
          {
              return new SmartEnumerable<T>(source);
          }
      }
      
      /// <summary>Wrapper methods for SmartEnumerable[T].</summary>
      
      public static class SmartEnumerableExt
      {
          /// <summary>Extension method to make life easier.</summary>
          /// <typeparam name="T">Type of enumerable</typeparam>
          /// <param name="source">Source enumerable</param>
          /// <returns>A new SmartEnumerable of the appropriate type</returns>
      
          public static SmartEnumerable<T> AsSmartEnumerable<T>(this IEnumerable<T> source)
          {
              return new SmartEnumerable<T>(source);
          }
      }
      
      /// <summary>
      /// Type chaining an IEnumerable&lt;T&gt; to allow the iterating code
      /// to detect the first and last entries simply.
      /// </summary>
      /// <typeparam name="T">Type to iterate over</typeparam>
      
      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification="This is too general to end in 'Collection'")]
      
      public class SmartEnumerable<T>: IEnumerable<SmartEnumerable<T>.Entry>
      {
          /// <summary>Enumerable to which we proxy</summary>
      
          readonly IEnumerable<T> _enumerable;
      
          /// <summary>Constructor.</summary>
          /// <param name="enumerable">Collection to enumerate. Must not be null.</param>
      
          public SmartEnumerable(IEnumerable<T> enumerable)
          {
              if (enumerable==null)
              {
                  throw new ArgumentNullException("enumerable");
              }
      
              this._enumerable = enumerable;
          }
      
          /// <summary>
          /// Returns an enumeration of Entry objects, each of which knows
          /// whether it is the first/last of the enumeration, as well as the
          /// current value.
          /// </summary>
      
          public IEnumerator<Entry> GetEnumerator()
          {
              using (IEnumerator<T> enumerator = _enumerable.GetEnumerator())
              {
                  if (!enumerator.MoveNext())
                  {
                      yield break;
                  }
      
                  bool isFirst = true;
                  bool isLast  = false;
                  int  index   = 0;
      
                  while (!isLast)
                  {
                      T current = enumerator.Current;
                      isLast = !enumerator.MoveNext();
                      yield return new Entry(isFirst, isLast, current, index++);
                      isFirst = false;
                  }
              }
          }
      
          /// <summary>Non-generic form of GetEnumerator.</summary>
      
          IEnumerator IEnumerable.GetEnumerator()
          {
              return GetEnumerator();
          }
      
          /// <summary>
          /// Represents each entry returned within a collection,
          /// containing the value and whether it is the first and/or
          /// the last entry in the collection's. enumeration
          /// </summary>
      
          public class Entry
          {
              internal Entry(bool isFirst, bool isLast, T value, int index)
              {
                  this._isFirst = isFirst;
                  this._isLast  = isLast;
                  this._value   = value;
                  this._index   = index;
              }
      
              /// <summary>The value of the entry.</summary>
      
              public T Value
              {
                  get
                  {
                      return _value;
                  }
              }
      
              /// <summary>Whether or not this entry is first in the collection's enumeration.</summary>
      
              public bool IsFirst
              {
                  get
                  {
                      return _isFirst;
                  }
              }
      
              /// <summary>Whether or not this entry is last in the collection's enumeration.</summary>
      
              public bool IsLast
              {
                  get
                  {
                      return _isLast;
                  }
              }
      
              /// <summary>The 0-based index of this entry (i.e. how many entries have been returned before this one)</summary>
      
              public int Index
              {
                  get
                  {
                      return _index;
                  }
              }
      
              readonly bool _isFirst;
              readonly bool _isLast;
              readonly T    _value;
              readonly int  _index;
          }
      }
      

      【讨论】:

      • 对我来说会显得有点矫枉过正。如果我到处都在做这种事情,我可能只会创建一个简单的ForEach 扩展方法,它会简单地迭代列表并为最后一项引发回调方法。看看这种方法是否比AsSmartEnumerable 更快会很有趣。
      • @James 是的,如果这是 SmartEnumerable 给你的全部,我同意 - 但它也会给你当前项目的索引,以及它是否是第一个项目列表。我们确实在不同的地方使用它,它使代码更具可读性(特别是当我们使用项目的索引时,否则必须在 foreach 循环之前声明一个索引计数器并在循环中递增它)跨度>
      【解决方案6】:

      如果您只有IEnumerable,则必须手动触发枚举器。这是一个示例扩展方法,可能对您有所帮助:

      public static class IEnumerableExtensions
      {
          public static void Action<T>(this IEnumerable<T> source, Action<T> sequenceElement, Action<T> lastElement)
          {
              if (source == null)
                  throw new ArgumentNullException("source");
      
              if (sequenceElement == null)
                  throw new ArgumentNullException("sequenceElement");
      
              if (lastElement == null)
                  throw new ArgumentNullException("lastElement");
      
              T element = default(T);
      
              using (var enumerator = source.GetEnumerator())
              {
                  if (enumerator.MoveNext())
                      element = enumerator.Current;
      
                  while (enumerator.MoveNext())
                  {
                      sequenceElement(element);
                      element = enumerator.Current;
                  }
      
                  lastElement(element);
              }
          }
      }
      

      你可以这样称呼它:

      var myElements = Enumerable.Range(1, 10);
      
      myElements.Action(value => Console.WriteLine("Something out of the sequence: " + value),
                          value => Console.WriteLine("The last element: " + value));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-03
        • 2014-05-22
        • 1970-01-01
        • 2023-03-25
        • 2020-11-26
        • 2014-03-20
        • 2013-10-16
        • 2019-10-22
        相关资源
        最近更新 更多