我有两个结构如下的列表。
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"} }
};
我希望得到来自modifiedTeams的驱动程序和codriver的所有ID,但如果在modifiedTeams中没有驱动程序/ codriver,则根据Team ID(T1,T2)从allTeams获取它。例如:来自codriver的ID T2队
Final Output:
{D2,C1,D1,C2}
有人可以帮助我如何通过C#中的LINQ(Lambda表达式)实现这一目标。
简单的C#代码: -
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);
}
}
}
答案 0 :(得分:1)
所以你要做的是left join
allTeams
到modified
小组。然后,如果左连接找到匹配的值,则获取该对象的id,否则为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();
仅获取ID:
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();
答案 1 :(得分:0)
我根据你的评论编辑我的答案。请找到以下代码。
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}
}
}
您可以在一个查询中编写逻辑。但为了说清楚,我已将它写在foreach中。
希望这有帮助
答案 2 :(得分:0)
好吧,显然你有办法检查司机是否“不在场”以及CoDriver是否“不在那里”。虽然你没有指定驱动程序何时不存在,但是从我的例子中我收集到的是,如果属性等于null。
但我们假设一个团队有两个职能:
bool DriverIsThere();
bool CoDriverIsThere();
现在您有一系列TeamIds
,并且您希望每个TeamId都生成两个DriverIds
的{{1}}
如果Drivers
有modifiedTeam
:
1如果TeamId
生成IsDriverThere()
,则从Driver.DriverId
的{{1}}集合中找到Team
并返回AllTeams
并返回Id
2如果Driver.DriverId
生成IsCodDriverThere()
,则从CoDriver.DriverId
的{{1}}集合中找到Teadm
并使用相同的'Id'并生成'CoDriver.DriverId`。
如果请求AllTeams
没有modifiedTeam
,或者Id
没有AllTeams
,则您没有提及该怎么办。我们假设您要抛出异常。
此要求的此代码可以在一个LINQ语句中编写。我相信其他人会试着这样回答。作为替代方案,我想推广Yield方法,因为我认为在这种情况下它会更具可读性和可维护性。
我认为您的ID是唯一的。为了增强查找效果,我会将modifiedTeams和allTeams放入词典中,以增强查找效果。
我不想改变你的类,所以让我们使用扩展方法。
请参阅Extension Methods Demystified
让我们首先定义IsThere:
Id
根据上面定义的要求获取团队并生成两个// 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
}
的函数非常简单:
DriverIds
更好的方法:使用委托来选择是否需要驱动程序或Codriver:
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
}
}
用法:
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(...);
}
}
现在从teamId到请求的driverIds:
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);
}
毕竟,带有一系列teamIds,modifiedTeams和allTeams并转换为请求输出的最终函数是一个很短的函数:
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
}