Linq-在其他两个对象之间选择周围的对象



我有一个复杂的谜题要给你
我有一种情况,我有一个对象集合,我要返回给定类型的对象之间的所有对象
我还有一个对象,我知道它在集合中,我也知道它在两个对象之间
所以我想返回一组位于给定类型的两个对象之间的周围对象(和self(。

这有意义吗?

以下是我迄今为止的一个示例:
此集合中有两个集合
此查询返回第一组对象,但我不检查已知对象是否在此集合内,并且不会继续搜索集合。

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"
}
*/

你明白我想做什么吗
Linq是最好的方法吗?还是应该使用recersive函数?

感谢

如果你真的想使用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;
    }
}

然后你可以做:

var objsBetween = GetBetween(objs, typeof(Between)).ToList();

我想出了一个解决方案,我从MoreLinq窃取了TakeUntil代码,并创建了另一个递归扩展方法
事实证明,对于我的需求,仅仅检查类型是不够的,我需要一个谓词:

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

然后像这样使用:

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();

所以,如果有人想知道的话,我之所以这么做是因为我想为Markdig解析的Markdowwn文档中的每个元素创建CSS选择器
因此,最终此代码将允许我获得两个HTMLBlock之间的元素的nth-of-type

最新更新