c # - Использование LinQ для поиска дублирующихся элементов в списке и обновление свойств объекта, если это так - PullRequest
0 голосов
/ 22 октября 2018

У меня есть список Все полеты типа объекта FLightInfo.

Если объект из списка имеет одинаковые номер рейса и время взлета.Я хочу объединить эти записи и добавить их количество пользователей

Пример: Это мой список:

  • FlightNumber 123 Взлет 12:00 Пользователи 5
  • FlightNumber 256 Взлет 3:00 Пользователи 6
  • FlightNumber 123 Взлет 12:00 Пользователи 8
  • FlightNumber 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

Ответы [ 3 ]

0 голосов
/ 22 октября 2018

Если я правильно понимаю ваш вопрос, вы можете сгруппировать List<FlightInfo> allFlights объекты по FlightNumber и Takeoff_time, а затем отсеять все записи, в которых не более одного элемента, с помощью groupedList = allFlights.Where(g => g.Count() > 1),

Затем можно объединить оставшиеся объекты, выбрав инициализацию анонимного типа с помощью groupedList.Select(x => new { x.Key.FlightNumber, x.Key.Takeoff_Time, SummedUserCount = x.Sum(s => s.UserCount) }).

0 голосов
/ 22 октября 2018

То, что вы ищете, может быть достигнуто с помощью 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;
}

Первый аргументto .GroupBy указывает анонимный тип, описывающий свойства, по которым вы хотите сгруппировать.Второй элемент определяет, что вы хотите в ваших списках результатов (по одному на группу).В этом случае нам нужен весь объект информации о рейсе.Третий параметр указывает, как вы хотите преобразовать каждую группу.В этом случае мы передаем каждый набор сгруппированных полетов методу, который суммирует UserCount и возвращает один FlightInfo с этим суммированным значением.

0 голосов
/ 22 октября 2018

Я сделал ваш 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. , предотвращая любые проблемы многопоточности с помощью оператора блокировки
  2. объединение записей

FlightManager

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,
    // ...
}

, но конструктор прояснит ваше намерение, что пользователь должен предоставить все данные заранее.Если вы используете библиотеку сериализации, это может оказаться невозможным.

...