[英]Linq - Select surrounding objects between two others
I've got a complexing puzzle for you.我有一个复杂的谜题要给你。
I have have a situation where I have a collection of objects and I what to return all the objects between objects of a given type.我有一种情况,我有一个对象集合,我要返回给定类型的对象之间的所有对象。
I also have a object that I know is inside that collection and I also know that it is inbetween the two objects.我还有一个 object,我知道它在那个集合中,我也知道它在两个对象之间。
So I want to return a set of surrounding objects (and self) that lay inbetween two objects of a given type.所以我想返回一组位于给定类型的两个对象之间的周围对象(和自身)。
Does this make sence?这有意义吗?
Here is an example that I have so far:这是我到目前为止的一个例子:
There are two sets inside this collection.这个系列里面有两套。
This query returns the first set of objects, but I do not check if the known object is within this set and it will not continue searching the collection.此查询返回第一组对象,但我不检查已知的 object 是否在此集合中,并且不会继续搜索集合。
class Between { }
class Known{}
var bob = new Known();
var objs = new object[]
{
"Outside",
new Between(),
"Inside",
bob,
"Inside",
new Between(),
"Outside",
new Between(),
"Inside",
"Inside",
new Between(),
"Outside"
};
var objsBetween = objs
.SkipWhile(x => x.GetType() != typeof(Between))
.Skip(1)
.TakeWhile(x => x.GetType() != typeof(Between)).ToList();
//...Result
/*
{
"Inside",
bob,
"Inside"
}
*/
Do you understand what I am trying to do?你明白我想要做什么吗?
Is Linq the best way to do it or should I use a recersive function? Linq 是最好的方法还是我应该使用反向 function?
Thanks谢谢
You could get it to work with Aggregate() if you really want to use LINQ, but I'd probably just create an iterator method because I think the code is clearer:如果你真的想使用 LINQ,你可以让它与Aggregate()一起工作,但我可能只是创建一个迭代器方法,因为我认为代码更清晰:
IEnumerable<object> GetBetween(IEnumerable<object> items, Type betweenType)
{
bool between = false;
foreach (object item in items)
{
if (item.GetType() == betweenType)
between = !between;
else if (between)
yield return item;
}
}
Then you could do:然后你可以这样做:
var objsBetween = GetBetween(objs, typeof(Between)).ToList();
I have come up with a solution, I stole the TakeUntil
code from MoreLinq and created another recurrsive Extension method.我想出了一个解决方案,我从MoreLinq窃取了TakeUntil
代码并创建了另一个递归扩展方法。
It also turnen out that for my requirements, checking for type is not enough, I needed a predicate:事实证明,对于我的要求,检查类型是不够的,我需要一个谓词:
static class Extensions
{
public static IEnumerable<TSource> TakeUntil<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
return _(); IEnumerable<TSource> _()
{
for (int i=0;i< source.Count();i++)
{
yield return source.ElementAt(i);
if (predicate(source.ElementAt(i), i))
yield break;
}
}
}
public static List<List<T>> SetsBetween<T>(this List<T> collection, Func<T, bool> betweenPredicate, List<List<T>> toReturn = null)
{
if (toReturn == null)
{
toReturn = new List<List<T>>();
}
var set = collection.SkipWhile(x => !betweenPredicate(x))
.TakeUntil((x, i) => (i > 0) && betweenPredicate(x))
.ToList();
toReturn.Add(set.Skip(1).SkipLast(1).ToList());
collection.RemoveAll(x => set.Contains(x));
if (collection.Any(x => betweenPredicate(x)))
{
collection.SetsBetween(betweenPredicate, toReturn);
}
return toReturn;
}
And then use it like:然后像这样使用它:
var bob = new Person();
var objs = new List<object>()
{
"Outside",
new Between(),
"Inside",
bob,
"Inside",
new Between(),
"Outside",
new Between(),
"Not this",
"Not this either",
new Between(),
"Outside"
};
var sets = objs.SetsBetween(x => x.GetType() == typeof(Between));
var bobSet = sets.Where(x => x.Contains(bob)).SelectMany(x => x).ToList();
So if anyone wonders, the reason I am doing this is because I wan to create CSS selectors for each element in a Markdowwn document parsed by Markdig .因此,如果有人想知道,我这样做的原因是因为我想为 Markdig 解析的Markdowwn文档中的每个元素创建 CSS 选择器。
So eventually this code will allow me to get the nth-of-type
of a element between two HTMLBlock
s.所以最终这段代码将允许我获得两个HTMLBlock
之间元素的nth-of-type
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.