1

I have 2 lists with below structure.

public class Team
{
    public string Id { get; set; }
    public Driver Driver { get; set; }
    public Driver Codriver { get; set; }
}

public class Driver
{
    public string DriverId { get; set; }
}

var modifiedTeams = new List<Team>
{
    new Team {Id = "T1", Driver = new Driver { DriverId = "D2" }, Codriver = new Driver { DriverId = "C1"} },
    new Team {Id = "T2", Driver = new Driver { DriverId = "D1"} }
};

var allTeams = new List<Team>
{
    new Team {Id = "T1", Driver = new Driver { DriverId = "D1" }, Codriver = new Driver { DriverId = "C1"} },
    new Team {Id = "T2", Driver = new Driver { DriverId = "D2"}, Codriver = new Driver { DriverId = "C2"} }
};

I want to get all the Id's of driver and codriver from modifiedTeams but if driver/codriver is not there in modifiedTeams then fetch it from allTeams based on Team ids(T1,T2) Eg: Id of codriver from Team T2

Final Output:

{D2,C1,D1,C2}

Can some one help me how I could achieve this via LINQ(Lambda expressions) in C#.

Simple C# code:-

List<string> allDriverCodriverIds = new List<string>();
foreach (var team in modifiedTeams)
{
    if (team.Driver != null && !string.IsNullOrEmpty(team.Driver.DriverId))
    {
        allDriverCodriverIds.Add(team.Driver.DriverId);
    }
    else {
        var existingTeam = allTeams.FirstOrDefault(e => e.Id.ToString() == team.Id);
        if (existingTeam != null && existingTeam.Driver != null && !string.IsNullOrEmpty(existingTeam.Driver.DriverId))
        {
            allDriverCodriverIds.Add(existingTeam.Driver.DriverId);
        }
    }
    if (team.Codriver != null && !string.IsNullOrEmpty(team.Codriver.DriverId))
    {
        allDriverCodriverIds.Add(team.Codriver.DriverId);
    }
    else
    {
        var existingTeam = allTeams.FirstOrDefault(e => e.Id.ToString() == team.Id);
        if (existingTeam != null && existingTeam.Codriver != null && !string.IsNullOrEmpty(existingTeam.Codriver.DriverId))
        {
            allDriverCodriverIds.Add(existingTeam.Codriver.DriverId);
        }
    }
}
7
  • 2
    "but it is not there" is quite fuzzy. How are you trying to do it? Please give us corresponding code. Commented Nov 17, 2017 at 7:28
  • Hi @apomene, I have updated my question hope this clarifies what I am trying to achieve. I do not have a LINQ query for the same.I am comparatively new to LINQ. Commented Nov 17, 2017 at 7:46
  • Where is what you have tried in linq? Commented Nov 17, 2017 at 8:07
  • @GiladGreen I haven't reached to the point where I can retrieve id's from both list. I am able to get all id's from single list via. List<string> allDriverCodriverIds = modifiedTeams.Select(app => app.Driver.DriverId).Concat(modifiedTeams.Select(app => app.Codriver.DriverId)).ToList(); Commented Nov 17, 2017 at 8:12
  • @KavyaShetty - in your question you state joining the lists.. where is the join query? Commented Nov 17, 2017 at 8:14

3 Answers 3

2

So what you are looking to do is to left join the allTeams to the modified teams. Then if the left join find a matching value you take the id of that object, otherwise of allTeams:

var result = (from a in allTeams
             join m in modifiedTeams on a.Id equals m.Id into mj
             from m in mj.DefaultIfEmpty()
             select new Team
             {
                 Id = a.Id,
                 Driver = m?.Driver ?? a.Driver,
                 Codriver = m?.Codriver ?? a.Codriver
             }).ToList();

For getting only the ids do:

var result = (from a in allTeams
              join m in modifiedTeams on a.Id equals m.Id into mj
              from m in mj.DefaultIfEmpty()
              select new [] { m?.Driver?.DriverId ?? a.Driver?.DriverId, 
                              m?.Codriver?.DriverId ?? a.Codriver?.DriverId
              }).SelectMany(i => i).ToList();
Sign up to request clarification or add additional context in comments.

2 Comments

This works with slight modification List<string> allDriverCodriverIds = (from a in allTeams join m in modifiedTeams on a.Id equals m.Id into mj from m in mj.DefaultIfEmpty() select new[] { (m.Driver != null && !string.IsNullOrEmpty(m.Driver.Id))?m.Driver.Id : a.Driver.Id, (m.Codriver != null && !string.IsNullOrEmpty(m.Codriver.Id))?m.Codriver.Id : a.Codriver.Id }).SelectMany(i => i).ToList(); Thanks for the help.
@KavyaShetty - if this helped you solve the problem please consider marking question as solved
0

I'm editing my answer as per your comment. Please find the code below.

public static void KvYQ()
            {
                List<Team> modifiedTeams = new List<Team>() {
                    new Team() {
                        Id="T1"
                        ,Driver=new Driver() {
                            DriverId="D2"
                        }
                        ,Codriver=new Driver() {
                            DriverId="C1"
                        }
                    }
                    ,new Team() {
                        Id="T2"
                        ,Driver=new Driver() {
                            DriverId="D1"
                        }
                    }
                };

                List<Team> allTeams = new List<Team>() {
                    new Team() {
                        Id="T1"
                        ,Driver=new Driver() {
                            DriverId="D1"
                        }
                        ,Codriver=new Driver() {
                            DriverId="C1"
                        }
                    }
                    ,new Team() {
                        Id="T2"
                        ,Driver=new Driver() {
                            DriverId="D2"
                        }
                        ,Codriver=new Driver() {
                            DriverId="C2"
                        }
                    }
                };    

                var driverdetails = modifiedTeams.Select(x => new Team()
                {
                    Driver = x.Driver,
                    Codriver = x.Codriver

                });

                foreach (var item in driverdetails)
                {
                    Driver d = (item.Driver == null) ? allTeams.Select(x => x.Driver).FirstOrDefault() : item.Driver;
                    Driver c = (item.Codriver == null) ? allTeams.Select(x => x.Codriver).FirstOrDefault() : item.Codriver;
                    Console.WriteLine(d.DriverId + " " + c.DriverId);
                    //{D2,C1}
                    //{D1,C1}
                }


            }

You can Write the logic in one query itself. But to make it clear, i've written it in foreach.

Hope this helps

2 Comments

Hi @RamVenkat, I want to get all the Id's of driver and codriver from modifiedTeams but if driver/codriver is not there in modifiedTeams then fetch it from allTeams based on Team ids(T1,T2) Eg: Id of codriver from Team T2. the output should be {D2, C1, D1, C2} where C2 is fetched from allteams as codriver for Team T2 is not there in modifiedTeams
The above code is with assumption that allTeams list will not be null and it will have all the details.
0

Ok, apparently you have a method to check whether a Driver is "not there" and whether a CoDriver is "not there". Although you don't specify when a Driver is not there, from your exemple I gather that this is if the property equals null.

But let's assume a Team has two functions:

bool DriverIsThere();
bool CoDriverIsThere();

Now you have a sequence of TeamIds, and you want to every TeamId to produce the DriverIds of two Drivers

If there is a modifiedTeam with TeamId: 1 If IsDriverThere(), produce Driver.DriverId, else find the Team from the collection of AllTeams with the same Id and return Driver.DriverId 2 If IsCodDriverThere(), produce CoDriver.DriverId, else find the Teadm from the collection of AllTeams with the same 'Id' and produce 'CoDriver.DriverId`.

You didn't mention what to do if there is no modifiedTeam with the requested Id, or if there is no AllTeams with this Id. Let's assume you want to throw exception.

This code for this requirement could be written in one LINQ statement. And I'm sure others will try to answer it this way. As an alternative, I'd like to promote the Yield method, because I think in this case it would be much more readable and maintainable.

I assume your IDs are unique. To enhance lookup, I'll put your modifiedTeams and allTeams into dictionaries, to enhance lookup.

I don't want to change your classes, so let's use extension methods.

See Extension Methods Demystified

Let's first define IsThere:

// returns true if Driver "is there"
public static bool IsThere(this Driver driver)
{
     return driver != null;
    // might be for some other reason, for instance: && !driver.IsSick
}

The function that takes a Team, and produces the two DriverIdsaccording to the requirements defined above is fairly straightforward:

public static IEnumerable<string> ToDriverIds(this Team team,
    Dictionary<string, Team> allTeams)
{
    if (team.Driver.IsThere())
        // Driver is there, yield return the Id
        yield return team.Driver.DriverId;
    else
    {   // Driver not available, fetch the Driver from allTeams
        // throw exception if there is no alternative team with this team ID
        Team alternativeTeam = allTeams[team.Id];
        if (alternativeTeam.IsDriverThere())
            yield return alternativeTeam.Driver.Id;
        else
           // Driver also not in alternative team: exception
           throw new InvalidOperationException("...");

        // do the same for coDriver
    }
}

An even nicer method: use a delegate to select whether you want the Driver or the Codriver:

public static Driver ToDriver(this Team team,
    Dictionary<string, Team> allTeams,
    Func<Team, Driver> driverSelector)
{
    Driver driver = driverSelector(team);
    if (driver.IsThere())
        return driver.Id;
    else
    {   // use allTeams:
        Team allternativeTeam = allTeams[team.Id];
        driver = friverSelector(alternativeTeam);
        if (driver.IsThere())
            return driver.Id;
        else
            throw new InvalidOperationException(...);
    }
}

Usage:

public static IEnumerable<string> ToDriverIds(this Team,
   Dictionary<string, Team> allTeams)
{
    // return the driverId of the driver:
    yield return Team.ToDriverId(allTeams, team => team.Driver);
    // yield return the driverId of the CoDriver:
    yield return Team.ToDriverId(allTeams, team => team.CoDriver);
}

Now from teamId to the requested driverIds:

public static IEnumerable<string> ToDriverIds(this string teamId,
    Dictionary<string, Team> modifiedTeams
    Dictionary<string, Team> allTeams)
{
    return modifiedTeams[teamId].ToDriverids(allTeams);
    // exception if there is no team with teamId
}

After all this, the final function that takes a sequence of teamIds, the modifiedTeams, and allTeams and converts into the requested output is a short one:

public static IEnumerable<string> ToIds(this IEnumerable<string> teamIds,
   IEnumerable<Team> modifiedTeams, IEnumerable<Team> allTeams)
{
    var modifiedTeamsLookup = modifiedTeams.ToDictionary(team => team.Id);
    var allTeamsLookup = allTeams.ToDictionary(team => team.Id);

    return teamIds
        .SelectMany(teamId => teamId.ToDriverIds(modifiedTeamsLookup,
            allTeamsLookup);

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.