c# - 使用 LinQ 查找列表中的重复项并在出现时更新对象属性

c# - Using LinQ to look for duplicate items in a list and updating object properties if so

我有一个 list 对象类型为 FLightInfo 的所有航班。

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

示例: 这是我的列表:

我希望输出像:

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

我把你的 FlightInfo 改成 class 并根据 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 class 来处理

  1. 使用锁定语句防止任何多线程问题
  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,
    // ...
}

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

你要找的可以用 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 和 returns 与该总和值相加 FlightInfo