简体   繁体   English

Linq - Select 周围两个其他对象之间

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM