使用 LinQ 在列表中查找重复项,如果存在,则更新对象属性



我有一个列表对象类型为 FLightInfo.

如果列表中的物体具有相同的航班号和起飞时间。 我想合并这些条目并添加其用户计数

示例:这是我的列表:

  • 航班号 123 起飞 12:00 用户 5
  • 航班号 256 起飞 3:00 用户 6
  • 航班号 123 起飞 12:00 用户 8
  • 航班号 651 起飞 5:00 用户 3

我希望输出如下所示:

FlightNumber 123  Takeoff 12:00 Users 13
FlightNumber 256  Takeoff 3:00  Users 6  
FlightNumber 651  Takeoff 5:00  Users 3

我的源代码:

struct FlightInfo
{
public string FlightNumber { get; set; }
public string Takeoff_time { get; set; }
public string Landing_time { get; set; }
public int UserCount { get; set; }
}
static List<FlightInfo> allFlights = new List<FlightInfo>();
//I read several files using multi-threading and create a FlightInfo object   
//and add it to the allFlights list
allFlights.Add(buildFlight(FlightNumber, Origination, Destination, Takeoff_time, Landing_time, UserCount);
//This is what I need to do
//if FlightNumber && testTakeOff object attributes are the same 
// I want to consolidate those entries and add the UserCount from those entries

你正在寻找的东西可以用GroupBy<TSource,TKey,TElement,TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>)来完成

使用你的对象定义,你可以做这样的事情

var consildatedFlights = allFlights.GroupBy(x => new {x.FlightNumber, x.Takeoff_time}, x => x,
(key, vals) => ConsolidateFlightInfo(vals));
foreach(var flight in consildatedFlights)
Console.WriteLine($"FlightNumber: {flight.FlightNumber}, Takeoff Time: {flight.Takeoff_time}, User Count: {flight.UserCount}");
public static FlightInfo ConsolidateFlightInfo(IEnumerable<FlightInfo> flights)
{
var list = flights.ToList();
var ret = list[0];
ret.UserCount = list.Sum(x => x.UserCount);
return ret;
}

.GroupBy的第一个参数指定一个匿名类型,用于描述要作为分组依据的属性。 第二项指定结果列表中所需的内容(每组一个(。 在本例中,我们需要整个航班信息对象。 第三个参数指定要如何转换每个分组。 在本例中,我们将每组分组航班传递给一个方法,该方法对UserCount求和并返回具有该总和值的单个FlightInfo

我把你的FlightInfo变成了一个类,并根据 C# 代码样式重命名了一些属性。我还添加了一个获取数据的构造函数。

class FlightInfo
{
public FlightInfo(string flightNumber, string origination, ...)
{
FlightNumber = flightNumber;
Origination = origination;
// ...
}
public string FlightNumber { get; set; }
public string Origination { get; set; }
public string Destination { get; set; }
public string TakeoffTime { get; set; }
public string LandingTime { get; set; }
public int UserCount { get; set; }
}

我们添加了一个 FlightManager 类来照顾

  1. 使用 Lock 语句防止任何多线程问题
  2. 合并条目

飞行管理器

class FlightManager
{
private object _lock = new object();
private List<FlightInfo> _flights = new List<FlightInfo>();
public void Add(FlightInfo info)
{
lock(_lock)
{
// look for existing flights
var existing = _flights.FirstOrDefault(f =>
{
return f.FlightNumber == info.FlightNumber
&& f.TakeoffTime == info.TakeoffTime;
});
// FirstOrDefault will return null if none found
if(existing == null)
{
// add as new flight
_flights.Add(info);
}
else
{
// add passenger count
existing.UserCount += info.UserCount;
}
}
}
}

用法

static FlightManager Manager = new FlightManager();
allFlights.Add(new FlightInfo(FlightNumber, Origination, Destination, TakeoffTime, LandingTime, UserCount);

POCO(数据对象(

如果删除构造函数,则还有另一种语法可以初始化FlightInfo

var flightInfo = new FlightInfo()
{
Origination = origination,
Destination = destination,
// ...
}

但是构造函数明确了您的意图,即用户必须提前提供所有数据。如果您使用的是序列化库,这可能是不可能的。

相关内容

  • 没有找到相关文章

最新更新