如何在 foreach 循环中验证元素是不是在集合中的最后一个?

Posted

技术标签:

【中文标题】如何在 foreach 循环中验证元素是不是在集合中的最后一个?【英文标题】: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() 的事情?这将避免很多其他的跑腿工作。 【参考方案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));

【讨论】:

以上是关于如何在 foreach 循环中验证元素是不是在集合中的最后一个?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在foreach循环中不能修改值类型实例

可以使用foreach遍历循环的条件

详细讲解foreach循环的用法

为什么阿里禁止在 foreach 循环里进行元素的 remove/add 操作

foreach循环

C#中foreach用法