Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Filter Items In A List According To Multiple Criteria

First, what my situation here is...

  • My SomeObject has a property string Status which I am interested in for this scenario.
  • Status property can contain "Open", "Closed", "Finished" values exactly.
  • I have a method called FilterObjects which returns a List<SomeObject>
  • Method accepts an argument same as its return type, List<SomeObject>
  • Method is supposed to filter according to following cases explained below and return the list of objects.
  • The List<SomeObject> I am sending as argument to my method is guaranteed to be in order (through their ID and type).

The cases are (all related to the string Status property I mentioned):

  1. If any item in the list contains Status = "Finished"; then eliminate all other elements that was in the original list and return only the object that has the "Finished" status.

  2. If any item does NOT contain Status = Finished but contains "CLOSED", I need to check if there is any other item that has the value of "Open" after that "CLOSED" one. You can think of this as a "a task can be closed, but can be reopened. But once it is finished, it cannot be reopened".

    If it contains a "CLOSED" and does not have any "OPEN" after that item, I will ignore all the items before CLOSED and only return CLOSED object. If it contains "OPEN" after any closed, I need to return anything AFTER that CLOSED, by excluding itself.

I also tried explain the same thing with my awesome MS Paint skills.

enter image description here

The object itself is not really a problem, but my method is something like this:

private List<SomeObject> FilterObjects(List<SomeObject> objectList)
{
    var objects = objectList;
    var returnList = new List<SomeObject>();
                    
    foreach (var obj in objects)
    {
        if (obj.Status == "Finished")
        {
            returnList.Add(obj);
            return returnList;
        }
    }

    return new List<SomeObject>();
}

Long story short, what would be the best and most efficient way to apply all this logic in this single method? Honestly, I couldn't go further than the first case I already implemented, which is the FINISHED. Could this whole thing be done with some LINQ magic?

It is guaranteed that I receive an ordered list AND I will never get items more than a couple of hundred so the collection will never be massive.

Many thanks in advance for the help.

like image 818
Michael Wayne Avatar asked Jan 27 '17 08:01

Michael Wayne


1 Answers

You can try something like that:

private List<SomeObject> FilterObjects(List<SomeObject> objectList)
{
    SomeObject finished = objectList.FirstOrDefault(o => o.Status.Equals("Finished"));
    if (finished != null) { return new List<SomeObject> { finished }; }

    List<SomeObject> closed = objectList.SkipWhile(o => !o.Status.Equals("Closed")).ToList();
    if (closed.Count == 1) { return closed; }
    if (closed.Count > 1) { return closed.Skip(1).ToList(); }

    // if you need a new list object than return new List<SomeObject>(objectList);
    return objectList;
}
like image 113
Kevin Wallis Avatar answered Sep 20 '22 17:09

Kevin Wallis