user2972346
user2972346

Reputation:

Grab next item in a list based on a field with LINQ

I have a list of employee's, and I'd like to select the next person in the list based on their status. I don't have my source code on hand, but basically my list is formed like this.

public class Employee
{
    public string Name { get; set; }
    public string Status{ get; set; }

        public Employee( string name, string status )
        {
            this.Status = status;
            this.Name = name;
        }
}

I add items like so.

        List<Employee> r = new List<Employee>();
        r.Add( new Employee( string Name, string status );

What I need is a way to search through the list at a starting name, say "Bob Smith", and get the next person in the list that has a status of "yes". However if it's at the end of the list, I'd start back at the beginning and go until I got to "Bob Smith" again.

I tried a clump of for loops, but it was cumbersome and awkward, and worst of all, didn't work.

This would all be in a function that returns a dictionary list, so I can use it with another function. In psuedo-code I'd like it to work kinda like this, so I can iterate through the dictionary of names in a for loop, using an int to grab items from it.

    public Dictionary<int,string> listToMail( int employeeNeeded )
    {
        Dictionary<int, string> tmpList = new Dictionary<int, string>();

        string lastEmployee = getLastEmployee();

        for( int x = 0; x < employeeNeeded; x++ )
        {
            /* find the next in the list that has a "yes" status. 
               If at the end of the list, start back at the beginning until we 
               reach the start by. If nothing found, exit out.*/

            tmpList.Add( x, EmployeeName );
        }

        if ( tmpList.Count > 0 )
        {
            return tmpList;

        } else {

            return null;
        }

    }

Upvotes: 1

Views: 1400

Answers (3)

Philip W
Philip W

Reputation: 791

I used lazyberezosky approach, but included all cases, its not very elegant but it works ;):

        List<Employee> list = new List<Employee>();
        list.Add(new Employee("Walter White", "yes"));
        list.Add(new Employee("Bob Smith", "no"));
        list.Add(new Employee("Walter Junior", "no"));

        //get first employee after Bob with status "yes"
        Employee result = list.SkipWhile(e => e.Name != "Bob Smith") // skip people until Bob Smith
                         .Skip(1) // go to next person
                         .SkipWhile(e => e.Status != "yes") // skip until status equal 'yes'
                         .FirstOrDefault(); // get first person, if any

        if (result == null)
        {
            //get the first employee in list with status "yes"
            result = list.SkipWhile(e => e.Status != "yes") // skip until status equal 'yes'
                         .FirstOrDefault(); // get first person, if any

            if (result == null)
            {
                //get Bob Smith if no employee has status "yes"
                result = list.SkipWhile(e => e.Name != "Bob Smith")
                        .FirstOrDefault();                               
            }
        }

A simpler approach would be:

        Employee res = list.SkipWhile(e => e.Name != "Bob Smith") // skip people until Bob Smith
                         .Skip(1) // go to next person
                         .SkipWhile(e => e.Status != "yes")
                         .Union(list.SkipWhile(e => e.Status != "yes"))
                         .FirstOrDefault();

if no employee has status "yes", res is null! so pay attention to not access the value of res without checking if its null...

and thanks again to lazyberezosky for the starting point ;)

Upvotes: 0

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236218

var person = 
   r.SkipWhile(e => e.Name != "Bob Smith") // skip people until Bob Smith
    .Skip(1) // go to next person
    .SkipWhile(e => e.Status != "yes") // skip until status equal 'yes'
    .FirstOrDefault(); // get first person, if any

if (person == null)
    person = r.TakeWhile(e => e.Name != "Bob Smith")
              .FirstOrDefault(e => e.Status != "yes");

Upvotes: 3

Lorentz Vedeler
Lorentz Vedeler

Reputation: 5301

Think this should work

public static Dictionary<int,string> listToMail(string startAtName, int needed)
    {
        var firstPart = r.SkipWhile(e => e.Name != startAtName);
        var secondPart = r.TakeWhile(e => e.Name != startAtName);

        var results = firstPart.Union(secondPart)
            .Where(e => e.Status == "yes")
            .Take(needed)
            .Select((e, i) => new { Key = i, Name = e.Name })
            .ToDictionary(kv => kv.Key, kv => kv.Name);
        if (results.Any())
            return results;
        else
            return null;
    }

Upvotes: 0

Related Questions