【问题标题】:How to get the item before current and after current in a dictionary with Linq / C#?如何使用 Linq / C# 在字典中获取当前和当前之后的项目?
【发布时间】:2011-05-19 01:48:40
【问题描述】:

我有一个项目字典,如果我选择一个项目,那么我会给出一个选项,前一个和下一个。我添加了一个代码示例,但我希望有更好/更快的方法来做到这一点,例如500个项目。

可能有 LINQ 选项之类的吗?

我检查了 Enumerator 但它只有一个moveNext 方法并且不能设置当前。

简单示例:

projectsDictionary

project 是存在于Dictionary 中的KeyValuePair

var match = false;
var save = new KeyValuePair<ExtendedProjectLightPlan, Page>();
var before = new KeyValuePair<ExtendedProjectLightPlan, Page>();
var after = new KeyValuePair<ExtendedProjectLightPlan, Page>();
foreach (var p in projects)
{
    before = save;
    save = p;

    if (match)
    {
        after = p;
        break;
    }

    if (p.Key.Id == project.Key.Id)
    {
        match = true;
    }                
}

【问题讨论】:

    标签: c# linq list foreach


    【解决方案1】:

    'current'之前的项目:

    items.TakeWhile(x => x != current).LastOrDefault();
    

    current”之后的项目:

    items.SkipWhile(x => x != current).Skip(1).FirstOrDefault();
    

    适用于整数类型,但会在序列末尾返回default(T)。将项目转换为 Nullable&lt;T&gt; 可能很有用,这样在第一个项目之前和最后一个项目之后返回 null

    【讨论】:

    • 对于一个列表,这是最好的解决方案。
    • 如果当前不在集合中,则返回“之前”的最后一项。我最终使用了items.Contains(current) ? items.TakeWhile(x =&gt; x != current).LastOrDefault() : default(current);
    • 或者,items.AsEnumerable().Reverse().SkipWhile(x =&gt; x != current).Skip(1).FirstOrDefault() 哈哈。 AsEnumerable() 是由于 stackoverflow.com/a/26241613
    【解决方案2】:

    您是否尝试过使用IndexOf()ElementAt() 方法??

        Int32 index = list1.IndexOf(item);
        var itemPrev = list1.ElementAt(index - 1);
        var itemNext = list1.ElementAt(index + 1);
    

    【讨论】:

    • 如果该项目是第一个元素,即在索引 0 或最后一个元素,则使用此代码您将得到一个异常。
    • @Marco:字典中的 before 和 after 是什么意思?你在使用SortedDictionary吗?
    • 我假设 OP 熟悉 IndexOutOfRangeException!
    【解决方案3】:

    LINQ 中没有内置任何东西来执行此操作,但您可以相当轻松地编写自己的...这是一个使用 .NET 4 中的Tuple 的实现。它将返回 n-2 项的序列,该序列最初具有 n项目 - 但您可以根据需要进行调整。

    public IEnumerable<Tuple<T, T, T>> WithNextAndPrevious<T>
        (this IEnumerable<T> source)
    {
        // Actually yield "the previous two" as well as the current one - this
        // is easier to implement than "previous and next" but they're equivalent
        using (IEnumerator<T> iterator = source.GetEnumerator())
        {
            if (!iterator.MoveNext())
            {
                yield break;
            }
            T lastButOne = iterator.Current;
            if (!iterator.MoveNext())
            {
                yield break;
            }
            T previous = iterator.Current;
            while (iterator.MoveNext())
            {
                T current = iterator.Current;
                yield return Tuple.Create(lastButOne, previous, current);
                lastButOne = previous;
                previous = current;
            }
        }        
    }
    

    请注意,根据 LukeH 的回答,字典是无序的……但希望以上内容对您有所帮助。

    【讨论】:

      【解决方案4】:

      字典没有内在的顺序,所以上一个和下一个项目的想法非常荒谬。

      【讨论】:

        【解决方案5】:

        我同意其他 cmets 关于在字典中排序的观点。但是由于字典提供IEnumerable&lt;KeyValuePair&lt;K, V&gt;&gt;,至少有一个小论据可以说它们有某种顺序。无论如何,这是我的建议:

        var ll = new LinkedList<ExtendedProjectLightPlan>();
        var qs =
            from p in projects
            let node = ll.AddLast(p.Key)
            select new { Project = p, Node = node, };
        
        var lookup = qs.ToDictionary(q => q.Project, q => q.Node);
        
        var current = (ExtendedProjectLightPlan)null; //Whatever the current one is.
        
        var previous = lookup[current].Previous.Value;
        var next = lookup[current].Next.Value;
        

        这将使从任何项目转移到上一个或下一个项目变得非常简单——而且速度非常非常快。 (虽然速度应该不是问题,因为这是针对 UI 的,对吧?)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多