如何通过IEnumerable访问foreach迭代中的下一个和前一个项目?

问题描述 投票:-1回答:4

我想在处理当前项目时访问下一个和前一个项目(如果在范围内)并迭代IEnumerable<object>,它缺少索引器(据我所知)。

我不想要一个List<object>集合或者一个数组来完成这个,虽然它是我现在唯一知道的选项。

如果可能的话,我也更愿意避免使用Linq表达式。

这就是我的方法目前定义的方式:

public static void PrintTokens(IEnumerable<object> tokens)
{
    foreach (var token in tokens)
    {
        // var next = ?
        // var prev = ?
    }
}
c# foreach ienumerable
4个回答
4
投票

你正常循环,但你当前的项目变为next,前一项是current,之前的项目是prev

object prev = null;
object current = null;
bool first = true;
foreach (var next in tokens)
{
    if (!first)
    {
        Console.WriteLine("Processing {0}. Prev = {1}. Next = {2}", current, prev, next);
    }

    prev = current;
    current = next;
    first = false;
}

// Process the final item (if there is one)
if (!first)
{
    Console.WriteLine("Processing {0}. Prev = {1}. Next = {2}", current, prev, null);
}

如果您使用的是C#7.0+,则可以编写

(prev, current, first) = (current, next, false);

而不是循环结束时的三个单独的语句。


1
投票

我写了一个扩展方法,它返回一个包含3个对象的元组:previous,current和next:

public static class Extensions
{
    public static IEnumerable<Tuple<T, T, T>> GetItems<T>(this IEnumerable<T> source)
        where T : class
    {
        if (source != null)
        {
            // skip the first iteration to be able to include next item
            bool skip = true;
            T previous = default(T), current = default(T), next = default(T);
            foreach (T item in source)
            {
                next = item;
                if (!skip)
                {
                    yield return new Tuple<T, T, T>(previous, current, next);
                }
                previous = current;
                current = item;
                skip = false;
            }
            if (!skip)
            {
                next = default(T);
                yield return new Tuple<T, T, T>(previous, current, next);
            }
        }
    }
}

希望能帮助到你。也许用自定义类而不是元组扩展。


0
投票

你可以尝试这种扩展方法。得到“尺寸”前一项和“尺寸”下一项和当前项目:

    public static System.Collections.Generic.IEnumerable<TResult> Select<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource> source, int size, System.Func<Queue<TSource>, TSource, Queue<TSource>, TResult> selector)
    {
        if (source == null)
        {
            throw new System.ArgumentNullException("source");
        }

        if (selector == null)
        {
            throw new System.ArgumentNullException("selector");
        }
        Queue<TSource> prevQueue = new Queue<TSource>(size);
        Queue<TSource> nextQueue = new Queue<TSource>(size);

        int i = 0;
        foreach (TSource item in source)
        {
            nextQueue.Enqueue(item);
            if (i++ >= size)
            {
                TSource it = nextQueue.Dequeue();
                yield return selector(prevQueue, it, nextQueue);
                prevQueue.Enqueue(it);
                if (prevQueue.Count > size)
                {
                    prevQueue.Dequeue();
                }
            }
        }

        while (nextQueue.Any())
        {
            TSource it = nextQueue.Dequeue();
            yield return selector(prevQueue, it, nextQueue);
            prevQueue.Enqueue(it);
            if (prevQueue.Count > size)
            {
                prevQueue.Dequeue();
            }
        }
    }

-1
投票

我认为原始IEnumerable不提供这个,但LinkedList提供它。


-1
投票

来自文档:

IEnumerable公开了一个枚举器,它支持一个简单的迭代。

因此,要实现您想要的目标,您可以遵循以下四种方法之一:

  • 在tokens变量上调用ToList() - 这样您就可以通过索引访问项目
  • 在IEnumerable上使用ElementAt()方法,但它会缺乏性能,因为每次调用此方法时都会枚举令牌
  • 正如您所建议的那样,将IEnumerable<object> tokens更改为IList<object> tokens
  • 编写自定义循环,保存以前,当前和下一个项目(下一个实际上是循环中的当前项目)
© www.soinside.com 2019 - 2024. All rights reserved.