许多多对多过滤器

发布于 2024-07-13 10:48:41 字数 1302 浏览 10 评论 0 原文

今天我们面临一个非常简单的问题,由于亲爱的谓词,这个问题变得更加简单。 我们有一种事件日志,并希望使用标准列表在客户端(Windows 窗体)对其进行过滤。 我们首先实施按多个类别进行过滤。

private List<Events> FilterEventsByCategory(List<Events> events,
                                        List<Category> categories) 
{
  return events.FindAll(ev => 
      categories.Exists(category => category.CategoryId==ev.CategoryId)); 
}

下一步是实现几个其他过滤器。 您是否知道一种很好的方法来将这些概括为也许不必为每个过滤器编写一个方法? 或者至少有一种干净的方式来获得我们想要同时应用的过滤器的动态列表。

客户端仍然使用框架 3.0,因此没有 LINQ。

更新: 我很难决定应该将我的解决方案归功于谁。 马克有一些很好的想法,并且非常善于解释它们。 如果我能更好地解释我的问题的话,很可能我就能从他那里得到答案。 最终,cmartin 提供的通用 Filter 类让我走上了正轨。 下面使用的 Filter 类可以在 cmartins 的答案中找到,而 User 类你可以自己想象。

var categoryFilter = new Filter<Event>(ev => categories.Exists(category => category.CategoryId == ev.CategoryId));
var userFilter = new Filter<Event>(ev => users.Exists(user => user.UserId == ev.UserId));

var filters = new List<Filter<Event>>();
filters.Add(categoryFilter);
filters.Add(userFilter);

var eventsFilteredByAny = events.FindAll(ev => filters.Any(filter => filter.IsSatisfied(ev)));
var eventsFilteredByAll = events.FindAll(ev => filters.All(filter => filter.IsSatisfied(ev)));

Today we faced a quite simple problem that were made even simpler by the dear predicates. We had a kind of event log and wanted to filter it client side (Windows Forms) using a list of criterias. We began by implementing to filter by a number of categories.

private List<Events> FilterEventsByCategory(List<Events> events,
                                        List<Category> categories) 
{
  return events.FindAll(ev => 
      categories.Exists(category => category.CategoryId==ev.CategoryId)); 
}

The next step is to implement a couple of other filters. Do you know of a nice way to generalize these to maybe somehow not having to write one method per filter? Or at least a clean way to have a dynamic list of filters that we want to apply simultaneously.

The clients are still on framework 3.0 so no LINQ.

Update:
I had a hard time deciding who I should give credit for my solution. Marc had some nice ideas and is really good at explaining them. Most probaly I would have got my answer from him if I only had explained my problem a little better. Ultimately it was the generic Filter class that cmartin provided that got me on track. The Filter class used below can be found in cmartins' answer and the User class you get to dream up yourself.

var categoryFilter = new Filter<Event>(ev => categories.Exists(category => category.CategoryId == ev.CategoryId));
var userFilter = new Filter<Event>(ev => users.Exists(user => user.UserId == ev.UserId));

var filters = new List<Filter<Event>>();
filters.Add(categoryFilter);
filters.Add(userFilter);

var eventsFilteredByAny = events.FindAll(ev => filters.Any(filter => filter.IsSatisfied(ev)));
var eventsFilteredByAll = events.FindAll(ev => filters.All(filter => filter.IsSatisfied(ev)));

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

生生不灭 2024-07-20 10:48:41

关于“所以没有 LINQ” - 您看过 LINQBridge 吗? 由于您使用的是 C# 3.0,这将是理想的...

我担心主要问题,我不完全理解您想要做什么以及想要避免什么 - 您能澄清一下吗? 但如果您使用 LINQBridge 方法,您可以使用连续的 .Where() 调用组合过滤器。

对这个问题的一种解释是,您不需要大量过滤方法 - 因此可能会将一个或多个进一步谓词传递到方法中 - 本质上作为 Func>Func> - 或者用纯 2.0 术语来说,一个 Converter>

private static List<Events> FilterEvents(
    List<Events> events,
    List<Category> categories,
    Converter<Events, Predicate<Category>> func)
{
    return events.FindAll(evt =>
        categories.Exists(func(evt)));
}

然后使用(如上)作为:

var result = FilterEvents(events, categories,
      evt => category => category.CategoryId==evt.CategoryId);

re "so no LINQ" - have you looked at LINQBridge? Since you are using C# 3.0 this would be ideal...

I'm afraid for the main question, I don't fully understand what you are trying to do and what you are trying to avoid - can you clarify at all? But if you use the LINQBridge approach you can combine filters using successive .Where() calls.

One interpretation of the question is that you don't want lots of filter methods - so perhaps pass in one or more further predicates into the method - essentially as a Func<Event, Func<Category, bool>> - or in pure 2.0 terms, a Converter<Event, Predicate<Category>>:

private static List<Events> FilterEvents(
    List<Events> events,
    List<Category> categories,
    Converter<Events, Predicate<Category>> func)
{
    return events.FindAll(evt =>
        categories.Exists(func(evt)));
}

which is then used (to be as above) as:

var result = FilterEvents(events, categories,
      evt => category => category.CategoryId==evt.CategoryId);
我要还你自由 2024-07-20 10:48:41

这是我要开始的一个非常基本的示例。

internal class Program
{
    private static void Main()
    {
        var ms = new Category(1, "Microsoft");
        var sun = new Category(2, "Sun");

        var events = new List<Event>
                         {
                             new Event(ms, "msdn event"),
                             new Event(ms, "mix"),
                             new Event(sun, "java event")
                         };

        var microsoftFilter = new Filter<Event>(e => e.CategoryId == ms.CategoryId);

        var microsoftEvents = FilterEvents(events, microsoftFilter);

        Console.Out.WriteLine(microsoftEvents.Count);
    }

    public static List<Event> FilterEvents(List<Event> events, Filter<Event> filter)
    {
        return events.FindAll(e => filter.IsSatisfied(e));
    }
}

public class Filter<T> where T: class
{
    private readonly Predicate<T> criteria;

    public Filter(Predicate<T> criteria)
    {
        this.criteria = criteria;
    }

    public bool IsSatisfied(T obj)
    {
        return criteria(obj);
    }
}

public class Event
{
    public Event(Category category, string name)
    {
        CategoryId = category.CategoryId;
        Name = name;
    }

    public int CategoryId { get; set; }
    public string Name { get; set; }
}

public class Category
{
    public Category(int categoryId, string name)
    {
        CategoryId = categoryId;
        Name = name;
    }

    public string Name { get; set; }
    public int CategoryId { get; set; }
}

Here's a very rudimentary sample of where I would start.

internal class Program
{
    private static void Main()
    {
        var ms = new Category(1, "Microsoft");
        var sun = new Category(2, "Sun");

        var events = new List<Event>
                         {
                             new Event(ms, "msdn event"),
                             new Event(ms, "mix"),
                             new Event(sun, "java event")
                         };

        var microsoftFilter = new Filter<Event>(e => e.CategoryId == ms.CategoryId);

        var microsoftEvents = FilterEvents(events, microsoftFilter);

        Console.Out.WriteLine(microsoftEvents.Count);
    }

    public static List<Event> FilterEvents(List<Event> events, Filter<Event> filter)
    {
        return events.FindAll(e => filter.IsSatisfied(e));
    }
}

public class Filter<T> where T: class
{
    private readonly Predicate<T> criteria;

    public Filter(Predicate<T> criteria)
    {
        this.criteria = criteria;
    }

    public bool IsSatisfied(T obj)
    {
        return criteria(obj);
    }
}

public class Event
{
    public Event(Category category, string name)
    {
        CategoryId = category.CategoryId;
        Name = name;
    }

    public int CategoryId { get; set; }
    public string Name { get; set; }
}

public class Category
{
    public Category(int categoryId, string name)
    {
        CategoryId = categoryId;
        Name = name;
    }

    public string Name { get; set; }
    public int CategoryId { get; set; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文