为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
陪伴而非守候 2022-11-22 16:21:12

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


我不想要求一个List<object>集合或一个数组来实现这一点,尽管这是我现在所知道的唯一选择。


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


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


public static void PrintTokens(IEnumerable<object> tokens)

{

    foreach (var token in tokens)

    {

        // var next = ?

        // var prev = ?

    }

}


查看完整描述

5 回答

?
德玛西亚99

TA贡献1484条经验 获得超3个赞

您像往常一样执行循环,但是您当前所在的项目变为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);

而不是循环末尾的三个单独的语句。


查看完整回答
反对 回复 2022-11-22
?
慕盖茨4494581

TA贡献1574条经验 获得超11个赞

For循环最好:


for (int i = 0; i < tokens.Count(); i++)

{

    token prv = i > 0 ? tokens[i-1] : null;

    token cur = tokens[i];

    token nxt = i < tokens.Count() ? tokens[i+1] : null;

}

然后就像你问的那样,你可以很容易地设置循环中的当前、上一个和下一个对象变量来使用。


编辑:我想知道为什么这不是一个好的解决方案,因为它是我正在使用的。


查看完整回答
反对 回复 2022-11-22
?
慕工程0101907

TA贡献0条经验 获得超5个赞

我写了一个扩展方法,它返回一个包含 3 个对象的元组:上一个、当前和下一个:


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);

            }

        }

    }

}

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


查看完整回答
反对 回复 2022-11-22
?
繁星点点滴滴

TA贡献0条经验 获得超3个赞

你可以试试这个扩展方法。它是获取“大小”上一个项目和“大小”下一个项目和当前项目:


    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();

            }

        }

    }


查看完整回答
反对 回复 2022-11-22
?
慕运维8079593

TA贡献1595条经验 获得超5个赞

除非我遗漏了什么,否则 for 循环不是最简单和最有效的方法吗?


for (int i = 0; i < tokens.Count(); i++)

{

    token previous = i > 0 ? tokens[i - 1] : null;

    token current = tokens[i];

    token next = i < tokens.Count() ? tokens[i + 1] : null;

}

那么你当前的循环索引就是实际的循环项,previous 和 next 很容易得到,不需要“你当前的循环对象是前一个对象”,也不需要循环外单独的'if'。


查看完整回答
反对 回复 2022-11-22
  • 5 回答
  • 0 关注
  • 10 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信