有什么像RegEx,但对于结构化对象?

时间:2017-05-09 18:39:10

标签: c# pattern-matching

我觉得我想要的东西应该存在,但我不知道它叫什么。所有搜索" regex for objects"只返回有关正常RegEx的教程和问题。搜索"模式匹配"返回有关C#7新模式匹配功能的新闻,这不是我想要完成的事情。

为了说明我之后的内容,假设你有以下课程:

public class Car
{
    public string Color { get; set; }
    public int MilesDriven { get; set; }
    public bool IsAllWheelDrive { get; set; }
}

然后假设您有一个具有随机和不同属性的Car对象列表。我希望能够在列表中搜索类似RegEx的模式,并获得模式发生的每个实例的开始和结束索引。

示例模式将是:

查找所有车轮在2辆蓝色轿车之间发生并且第一辆蓝色轿车上行驶超过1000英里的情况。

查找红色汽车紧随其后至少有2辆绿色汽车的所有情况,最后是一辆行驶不到100英里的汽车。

这是一个人为的问题,但我想知道是否存在这样的问题,最好是现有的C#库。

道歉,如果"模式匹配"不是这个问题的适用标签,但正如我所说的那样,我真的不知道如果有的话,可以称之为。

1 个答案:

答案 0 :(得分:0)

您正在寻找的是过滤器概念。 C#确实为列表提供了这样一个概念的应用程序,但是如果你不只是试图过滤对象的属性,它会变得复杂。 Microsoft通过LINQ使用this postthis post作为示例,使C#的过滤功能具有通用性:

Filtering collections in C#

基本上语法是:

var newlist = list.linqquery1.linquery2...linqueryN.Where(s.x condition);

当然,如果它足够简单,你可以做到以下几点:

var newlist = list.Where(s.x condition);

但是您的问题还要求根据列表中的后续项目进行选择。这要复杂得多,因为除非将数据附加到列表中的元素,否则您将无法访问这些元素。例如,如果您的listelem实际上是一个doubly linked list节点,您可以在病房列表中向前看,仅基于前向节点参考并运行这样的条件(检查两个绿色)汽车跟随):

var green2follows = carlist.Where(s.next.type == greencar && s.next.next.type == greencar);

但是,如果你自己用迭代来表达这种情况,你可以对使用双链表的情况进行总结。不幸的是,因为LINQ主要用于基于枚举的查询,所以你必须找到解决方法来使用微软内置的微软进行过滤(虽然这不是微软独有的,通常你不在查询中包含局部性)This post涵盖那个结论。

要迭代地执行此操作,您将创建一个for循环并针对i + 1和i + 2值的汽车进行测试。请小心,因为这会使先前的值变得混乱(i-n)迭代器可能对此有好处以避免错误,尽管我不确定c#是否像其他语言一样支持迭代器算法以允许您前后移动。您可能被迫制作自定义迭代器以通常定义此类过滤器。

编辑:你可以避免创建一个自定义迭代器,只创建一个迭代器返回的自定义对象,它通过迭代器块支持向前和向后查看(比如answer suggest in this post

你可能会做的是这样的事情:

HandleObject<T>...
...
public bool backwardsWhere(condition)...
public bool forwardsWhere(condition)...
public bool backwardsNWhere(n, condition);
public bool forwardsNWhere(condition);
//other forwards filter functions for convienience

// get back the element that we wraped
public T get();



static IEnumerable<T> iteratorBlock(List<T> list) 
{ 
    foreach (int i = 0; i < list.Length; i++)
    { 
        // yield means a new HandleObject is only created upon access, and
        // need not be stored otherwise
        yield return HandleObject<T>(i, list); 
    } 
}

不使用你的列表和LINQing,而是使用这个迭代器而不是模板列表,这样你就不必在C#中处理讨厌的迭代器语义来创建你自己的whilist仍然能够实现所有的功能你需要查看清单。

var customIterableFromBlock = iteratorBlock<Car>(carlist);
var selectedCars = from handleCar in customIterableFromBlock
where ... //handleCar.backwardsWhere(...)&& handleCar.forwardsWhere(...) 
          //handleCar.get().x == condition etc
select Car
{
    //get Car from handleCar.get()
};

您在i构造函数中包含HandleObject和列表本身的原因是允许根据传入的位置i向前和向后搜索列表。