我正在寻找优化我的LINQ查询的方法。
课程:
public class OffersObject
{
public List<SingleFlight> Flights { get; set; }
public List<Offer> Offers { get; set; } = new List<Offer>();
}
public class SingleFlight
{
public int Id { get; set; }
public string CarrierCode { get; set; }
public string FlightNumber { get; set; }
}
public class Offer
{
public int ProfileId { get; set; }
public List<ExtraOffer> ExtraOffers { get; set; } = new List<ExtraOffer>();
}
public class ExtraOffer
{
public List<int> Flights { get; set; }
public string Name { get; set; }
}样本对象:
var sampleObject = new OffersObject
{
Flights = new List<SingleFlight>
{
new SingleFlight
{
Id = 1,
CarrierCode = "KL",
FlightNumber = "1"
},
new SingleFlight
{
Id = 2,
CarrierCode = "KL",
FlightNumber = "2"
}
},
Offers = new List<Offer>
{
new Offer
{
ProfileId = 41,
ExtraOffers = new List<ExtraOffer>
{
new ExtraOffer
{
Flights = new List<int>{1},
Name = "TEST"
},
new ExtraOffer
{
Flights = new List<int>{2},
Name = "TEST"
},
new ExtraOffer
{
Flights = new List<int>{1,2},
Name = "TEST"
}
}
}
}
};LINQ查询的目标:
清单:
{ int ProfileId, string CommercialName, List<string> fullFlightNumbers }FullFlightNumber应该由航班的"Id关联“创建。它创建如下:{CarrierCode} {FlightNumber}
到目前为止,我所拥有的(工作正常,但不是最快的方式):
var result = sampleObject.Offers
.SelectMany(x => x.ExtraOffers,
(a, b) => {
return new
{
ProfileId = a.ProfileId,
Name = b.Name,
FullFlightNumbers = b.Flights.Select(f => $"{sampleObject.Flights.FirstOrDefault(fl => fl.Id == f).CarrierCode} {sampleObject.Flights.First(fl => fl.Id == f).FlightNumber}").ToList()
};
})
.ToList();最后注
在我看来不对的地方是:
.Select(f => $"{sampleObject.Flights.FirstOrDefault(fl => fl.Id == f)?.CarrierCode} {sampleObject.Flights.FirstOrDefault(fl => fl.Id == f)?.FlightNumber}").ToList()我基本上是在寻找一种方式“加入”这两个名单的OffersObject航班的Id。
任何小费都会得到赏识。
发布于 2022-04-08 20:26:57
如果在sampleObject.Flights中只定义了几个航班,那么使用数字键进行顺序搜索是很难克服的。
但是,如果航班数量比报价次数多(1000 s或更多),我建议将航班列表加载到字典中,并将Id作为有效查找的关键。类似于:
var flightLookup = sampleObject.Flights.ToDictionary(f => f.Id);然后将FullFlightNumbers计算为
FullFlightNumbers = b.Flights
.Select(flightId => {
flightLookup.TryGetValue(flightId, out SingleFlight flight);
return $"{flight?.CarrierCode} {flight?.FlightNumber}";
})
.ToList()如果找不到匹配,上面的TryGetValue将悄悄地返回一个空值。如果您知道匹配将始终存在,则查找冷将交替编码为:
SingleFlight flight = flightLookup[flightId];上面的语句还使用lambda语句。简而言之,lambda函数可以将表达式块或语句块作为主体。有关更多信息,请参见C#参考。
发布于 2022-04-09 05:23:29
我建议将双.FirstOrDefault()方法替换为.IntersectBy()。它可以在System.Linq名称空间中使用,从.NET 6开始。
.IntersectBy()基本上通过将sampleObject中的每个航班的航班ID与ExtraOffers.Flights中的航班ID相匹配来过滤ExtraOffers.Flights。
在下面的代码中,fl => fl.Id是sampleObject.Flights的键选择器(即fl是SingleFlight)。
var result = sampleObject.Offers
.SelectMany(x => x.ExtraOffers,
(a, b) => {
return new
{
ProfileId = a.ProfileId,
Name = b.Name,
FullFlightNumbers = sampleObject.Flights
.IntersectBy(b.Flights, fl => fl.Id)
.Select(fl => fl.FullFlightNumber) // alternative 1
//.Select(fl => $"{fl.CarrierCode} {fl.FlightNumber}") // alternative 2
.ToList()
};
})
.ToList();在我的建议中,我将属性FullFlightNumber添加到SingleFlight中,这样Linq语句看起来就稍微干净了一些:
public class SingleFlight
{
public int Id { get; set; }
public string CarrierCode { get; set; }
public string FlightNumber { get; set; }
public string FullFlightNumber => $"{CarrierCode} {FlightNumber}";
}如果定义SingleFlight.FullFlightNumber对您来说是不可能的/不可取的,则可以使用代码建议中的第二个选项。
例如小提琴这里。
https://stackoverflow.com/questions/71799656
复制相似问题