Как получить элемент до текущего и после текущего в списке с Linq/С#?
У меня есть список проектов, и если я выберу проект, я дам опцию предыдущий и следующий. У меня есть пример быстрого кода, но я надеюсь, что есть лучший/более быстрый способ сделать это, например, 500 проектов.
Возможно, есть опция linq или что-то еще?
Я проверил enumarator, но у меня есть только moveNext en не может установить текущий.
Быстрый пример:
проекты - это словарь
project - ключевая пара, которая существует в словаре
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;
}
}
Ответы
Ответ 1
В 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;
}
}
}
Обратите внимание, что в соответствии с ответом LukeH словари неупорядочены... но, надеюсь, вы все равно сможете помочь вам.
Ответ 2
Пробовали ли вы методы IndexOf()
и ElementAt()
?
Int32 index = list1.IndexOf(item);
var itemPrev = list1.ElementAt(index - 1);
var itemNext = list1.ElementAt(index + 1);
Ответ 3
Элемент перед 'current
':
items.TakeWhile(x => x != current).LastOrDefault();
Элемент после 'current
':
items.SkipWhile(x => x != current).Skip(1).FirstOrDefault();
Хорошо работает для интегральных типов, но вернет default(T)
в конце последовательности. Возможно, было бы полезно добавить элементы в Nullable<T>
, чтобы перед первым элементом и после последнего элемента вернуть null
.
Ответ 4
Словари не имеют внутреннего порядка, поэтому идея предыдущих и последующих статей довольно бессмысленна.
Ответ 5
Я согласен с другими комментариями относительно заказа в словарях. Но поскольку словари предлагают 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;
Это должно сделать очень простым переход от любого проекта к предыдущему или следующему - и это будет очень быстро. (Хотя скорость не должна быть проблемой, так как это для пользовательского интерфейса, верно?)