Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter a list of objects given a single object

Tags:

c#

.net

I want a method that accepts a list of objects, and then the 'filter object' (which is the same type as the list of objects). I'm able to do it (inefficiently) on a small scale but also quite fixed - I'd like it to be a generic method so I can pass in the type so it can apply to anything.

Example:

public class Program {
    public void Main(string[] args) {
        var listOfObjects = new List<MyClass> {
            new MyClass { ID = 1, Name = "Object 1" },
            new MyClass { ID = 2, Name = "Object 2" },
            new MyClass { ID = 3, Name = "Object 2" }
        };
        var filter = new MyClass { Name = "Object 2" };

        // Should return only the first object in the list, since
        // the filter's Name = "Object 2", all items in the list
        // where the property equals "Object 2" will be filtered out
        var filteredList = FilterObjects(listOfObjects, filter);
    }
}

public class MyClass {
    public int ID { get; set; }
    public string Name { get; set; }
}

public class MyTest {
    public List<MyClass> FilterObjects(List<MyClass> objects, MyClass filter) {
        // first check if the filter is just an empty new instance
        // if a user passes in an empty filter then they are not
        // filtering anything, therefore 
        if (filter == new MyClass()) return objects;

        var filteredList = new List<MyClass>();
        foreach (var item in objects) {
            // if this item passes the test for the filter
            // (check if any of the properties are equal to the
            // filter properties - if so, then this item is not
            // is not a match, and we cannot add it to the list)
            if (item.ID != filter.ID && item.Name != filter.Name)
                filteredList.Add(item);
            // What I want is a faster and more consolidated way of
            // checking all the properties.
        }
        return filteredList;
    }
}

EDIT: Is there any way to do this also using reflection?

EDIT2: Just wanted to clarify that my example here is just a simple template. I am working with an object that has 20+ properties and would love to not have to make a huge if statement if possible.

EDIT3: I should also mention that the filter object the user passes in can be incomplete, e.g. they can pass in a MyClass object without the ID (just the Name property) because when it reaches my Controller, that MyClass object will automagically fill in ID with a default value. I can check if it is a default value by creating a new instance of MyClass - new MyClass() and for every property, if it equals what the default value would be then ignore that property for filtering because the user didn't want that property filtered. But think of this concept on a larger scale where I have 20+ properties and a user wants to filter out all objects but ONLY wants to use 3 of those properties to filter from. The other 17+ properties will not have an equality check.

like image 334
Matt D Avatar asked Dec 04 '25 00:12

Matt D


1 Answers

It sounds like what you want are generic statements.

It isn't super straightforward but something like this should work:

public static IEnumerable<T> Filter<T>(this IEnumerable<T> results, Filter filter)
    {
        var types = results.GetType().GetProperties();

        foreach (var filter in filter.Filters)
        {
            Type type = results.GetType();
            filter.ColumnName = filter.ColumnName.Replace(" ", "");
            var pred = BuildPredicate<T>(filter.ColumnName, filter.FilterValue);
            if (filter.ColumnName != null && filter.FilterValue != null)
            {
                results = results.Where(w =>
                {                        
                    return w.GetType().GetProperty(filter.ColumnName).GetValue(w, null).ToString().ToLowerInvariant().Contains(filter.FilterValue.ToLowerInvariant());
                });
            }
        }

        return results;
    }

The filter object looks something like:

public class Filter
{
   public string ColumnName {get; set; }
   public string Value { get; set; }
   //Other properties for Asc / Desc and more
}

And then on any List like List or List you would essentially do:

var results = MyList.Filter(new Filter() { ColumnName = "LastName"; Value = "Smith" });

which gets translated to a Function that if typed manually would look like:

var results = MyList.Where(w => w.LastName == "Smith");

This example however is rough, no type checking for starters.

like image 147
Austin T French Avatar answered Dec 05 '25 15:12

Austin T French



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!