Bob*_*hiv 32 c# linq ienumerable
我有一个自定义类型的IEnumerable.(我是从SelectMany那里得到的)
我在IEnumerable中也有一个项目(myItem),我希望IEnumerable中的上一个和下一个项目.
目前,我正在做这样的想法:
var previousItem = myIEnumerable.Reverse().SkipWhile(
i => i.UniqueObjectID != myItem.UniqueObjectID).Skip(1).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
我可以通过简单地省略来获得下一个项目.Reverse.
或者,我可以:
int index = myIEnumerable.ToList().FindIndex(
i => i.UniqueObjectID == myItem.UniqueObjectID)
Run Code Online (Sandbox Code Playgroud)
然后.ElementAt(index +/- 1)用来获取上一个或下一个项目.
"更好"包括性能(内存和速度)和可读性的组合; 可读性是我的主要关注点.
Bin*_*ier 39
首先
"更好"包括性能(内存和速度)的组合
一般来说,你不能同时拥有这两者,经验法则是,如果你优化速度,它会花费内存,如果你优化内存,它会花费你的速度.
有一个更好的选择,在内存和速度前端都表现良好,并且可以以可读的方式使用(我对功能名称不满意,但是,FindItemReturningPreviousItemFoundItemAndNextItem有点拗口).
所以,它看起来像是自定义查找扩展方法的时候了...
public static IEnumerable<T> FindSandwichedItem<T>(this IEnumerable<T> items, Predicate<T> matchFilling)
{
if (items == null)
throw new ArgumentNullException("items");
if (matchFilling == null)
throw new ArgumentNullException("matchFilling");
return FindSandwichedItemImpl(items, matchFilling);
}
private static IEnumerable<T> FindSandwichedItemImpl<T>(IEnumerable<T> items, Predicate<T> matchFilling)
{
using(var iter = items.GetEnumerator())
{
T previous = default(T);
while(iter.MoveNext())
{
if(matchFilling(iter.Current))
{
yield return previous;
yield return iter.Current;
if (iter.MoveNext())
yield return iter.Current;
else
yield return default(T);
yield break;
}
previous = iter.Current;
}
}
// If we get here nothing has been found so return three default values
yield return default(T); // Previous
yield return default(T); // Current
yield return default(T); // Next
}
Run Code Online (Sandbox Code Playgroud)
如果需要多次引用项目,可以将结果缓存到列表中,但它会返回找到的项目,前面跟上一项,然后是下面的项目.例如
var sandwichedItems = myIEnumerable.FindSandwichedItem(item => item.objectId == "MyObjectId").ToList();
var previousItem = sandwichedItems[0];
var myItem = sandwichedItems[1];
var nextItem = sandwichedItems[2];
Run Code Online (Sandbox Code Playgroud)
如果第一个或最后一个项目可能需要根据您的要求进行更改,则返回默认值.
希望这可以帮助.
spe*_*der 19
为了便于阅读,我将加载IEnumerable到链接列表中:
var e = Enumerable.Range(0,100);
var itemIKnow = 50;
var linkedList = new LinkedList<int>(e);
var listNode = linkedList.Find(itemIKnow);
var next = listNode.Next.Value; //probably a good idea to check for null
var prev = listNode.Previous.Value; //ditto
Run Code Online (Sandbox Code Playgroud)
PHe*_*erg 13
通过创建用于为当前元素建立上下文的扩展方法,您可以使用如下的Linq查询:
var result = myIEnumerable.WithContext()
.Single(i => i.Current.UniqueObjectID == myItem.UniqueObjectID);
var previous = result.Previous;
var next = result.Next;
Run Code Online (Sandbox Code Playgroud)
扩展名将是这样的:
public class ElementWithContext<T>
{
public T Previous { get; private set; }
public T Next { get; private set; }
public T Current { get; private set; }
public ElementWithContext(T current, T previous, T next)
{
Current = current;
Previous = previous;
Next = next;
}
}
public static class LinqExtensions
{
public static IEnumerable<ElementWithContext<T>>
WithContext<T>(this IEnumerable<T> source)
{
T previous = default(T);
T current = source.FirstOrDefault();
foreach (T next in source.Union(new[] { default(T) }).Skip(1))
{
yield return new ElementWithContext<T>(current, previous, next);
previous = current;
current = next;
}
}
}
Run Code Online (Sandbox Code Playgroud)