Как получить элемент до текущего и после текущего в словаре с Linq / C #? - PullRequest
15 голосов
/ 02 декабря 2010

У меня есть словарь проектов, и если я выберу проект, я дам вариант предыдущий и следующий.Я добавил пример кода, но я надеюсь, что есть лучший / более быстрый способ сделать это, например, для 500 проектов.

Возможно, есть опция LINQ или что-то в этом роде?

Я проверил Enumerator, но он имеет только метод moveNext и не может установить текущий.* Быстрый пример:

projects - это Dictionary.

project - это KeyValuePair, существующий в Dictionary.

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

Ответы [ 5 ]

16 голосов
/ 15 мая 2012

Пункт до 'current':

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

Пункт после 'current':

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

Хорошо работает для целочисленных типов, но вернет default(T) в конце последовательности. Может быть полезно привести элементы к Nullable<T> так, чтобы перед первым элементом и после последнего элемента вместо него возвращалось null.

16 голосов
/ 02 декабря 2010

Вы пробовали использовать методы IndexOf() и ElementAt() ??

    Int32 index = list1.IndexOf(item);
    var itemPrev = list1.ElementAt(index - 1);
    var itemNext = list1.ElementAt(index + 1);
14 голосов
/ 02 декабря 2010

Нет ничего встроенного в LINQ, чтобы сделать это, но вы могли бы написать свой собственный довольно легко ... вот реализация, которая использует Tuple из .NET 4. Она возвратит 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;
        }
    }        
}

Обратите внимание, что согласно ответу ЛукиХ, словари не упорядочены ... но, надеюсь, вышеизложенное поможет вам в любом случае.

5 голосов
/ 02 декабря 2010

Словари не имеют собственного упорядочения, поэтому идея предыдущих и следующих элементов в значительной степени бессмысленна.

1 голос
/ 02 декабря 2010

Я согласен с другими комментариями относительно порядка в словарях. Но поскольку словари предлагают IEnumerable<KeyValuePair<K, V>>, есть, по крайней мере, небольшой аргумент, чтобы сказать, что у них есть какой-то порядок. Во всяком случае, вот мое предложение:

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;

Это должно сделать очень простым переход от любого проекта к предыдущему или следующему - и это будет очень очень быстро. (Хотя скорость не должна быть проблемой, так как это для пользовательского интерфейса, верно?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...