Использование словаря> найти наиболее распространенные вхождения в списке в C # - PullRequest
0 голосов
/ 07 июня 2018

Предполагая, что мой код C # определен, как показано ниже, я хотел бы вернуть на консоль вывод, показывающий тип топлива, наиболее часто встречающийся в Списке или автомобилях.

// set delegates defining rules as a function that takes list of cars and returns an int
Func<List<Car>, int> CountElectric = (cars) => cars
    .GroupBy(c => c.IsElectric == true).Count(); // count electric cars

Func<List<Car>, int> CountGassoline = (cars) => cars
    .GroupBy(c => c.FuelType == FuelTypes.Gassoline).Count(); // count cars using gassoline

Func<List<Car>, int> CountDiesel = (cars) => cars
    .GroupBy(c => c.FuelType == FuelTypes.Diesel).Count(); // Count cars using diesel

// Add rules to dictionary of (Key=CarType, Value=Func<List<Car>, bool>
CarsRules = new Dictionary<CarType, Func<List<Car>, int>>()
{
    {FueldType.Electric, CountElectric},
    {FueldType.Diesel,CountDiesel},
    {FueldType.Gassoline, CountGassoline}
};

// Create List of Cars and add some cars
List<Car> cars = new List<Car>();

cars.Add(new Car() 
{Id = Guid, Name = "Tesla", IsElectric = true, FuelType = FuelTypes.Electric};

cars.Add(new Car() 
{Id = Guid, Name = "VW", IsElectric = false, FuelType = FuelTypes.Gassoline};

cars.Add(new Car() 
{Id = Guid, Name = "Toyota", IsElectric = false, FuelType = FuelTypes.Gassoline};

cars.Add(new Car() 
{Id = Guid, Name = "Volvo", IsElectric = false, FuelType = FuelTypes.Diesel};

В приведенном выше спискеавтомобили, Gassoline является наиболее распространенным.Как мне это узнать?То есть я хочу отобразить на консоли только «Gassoline»

Если бы у меня была привязка в списке выше, например, 2 машины с бензином и 2 машины с дизельным, как бы я нашел и возвратил оба?То есть я хочу отобразить на консоли оба «Gassoline» и «Diesel»

Мне трудно понять такую ​​структуру, и я думаю сделать это старомодным способом, как показано ниже, но для меня ясно, чтобыть более элегантным способом сделать это с делегатами Func

public List<string> GetMostUsedFuelTypes(List<Car> cars)
{
    List<string> winners = new List<string>();

    int CountElectric = 0;
    int CountGassoline = 0;
    int CountDiesel = 0;

    foreach(var car in cars)
    {
        // Count and return fuel type that occurs most, if a tye, return the highest counts
    }

    return winners;
}

Ответы [ 5 ]

0 голосов
/ 08 июня 2018

Поскольку вы специально хотите использовать словарь "CarsRules" в качестве драйвера для этого, вы можете адаптировать мой другой ответ к размеру;но сначала вам нужно исправить ошибку в Count* Func s.На данный момент они возвращают ответ 0, 1 или 2, независимо от того, сколько машин вы добавили в список;и это не возвращает то, что вы думаете. Например, если вы поместите одну машину с бензином в список, то CountElectric вернет 1 .Чтобы исправить это ...

Func<List<Car>, bool> CountElectric = (cars) => cars.GroupBy(c => c.IsElectric == true).Count();

должно быть

Func<List<Car>, bool> CountElectric = (cars) => cars.Count(c => c.IsElectric == true);

И если тип IsElectric равен bool (вместо bool?), то вы также можете удалить==true, чтобы сделать его еще проще.

Это изменение необходимо сделать для всех 3 из этих Func s.

Так что теперь `Func's в словаре делают то, что требуетсячтобы ответить на вопрос, вы можете просто адаптировать мой предыдущий ответ следующим образом:

var fuelTypeCountDictionary = CarsRules
    .ToDictionary(x => x.Key, x => x.Value.Invoke(cars));
var max = fuelTypeCountDictionary.Values.Max();
var maxFuelTypes = fuelTypeCountDictionary.Where(x => x.Value == max).Select(x => x.Key);
Console.WriteLine(string.Join(", ", maxFuelTypes));
0 голосов
/ 08 июня 2018

Ваша структура Dictionary<CarType, Func<List<Car>, int>> не тот тип, чтобы делать подобные вещи.Вы можете объединить два int значения, чтобы получить точное число, если попытаетесь объединить типы с перекрывающимися подмножествами.

Вот что я бы сделал:

var CarsRules = new Dictionary<FuelTypes, Func<List<Car>, IEnumerable<Car>>>()
{
    { FuelTypes.Electric, cs => cs.Where(c => c.IsElectric) },
    { FuelTypes.Diesel, cs => cs.Where(c => c.FuelType == FuelTypes.Diesel) },
    { FuelTypes.Gassoline, cs => cs.Where(c => c.FuelType == FuelTypes.Gassoline) },
}

List<Car> cars = new List<Car>()
{
    new Car(Guid.NewGuid(), "Tesla", true, FuelTypes.Electric),
    new Car(Guid.NewGuid(), "VW", false, FuelTypes.Gassoline),
    new Car(Guid.NewGuid(), "Toyota", false, FuelTypes.Gassoline),
    new Car(Guid.NewGuid(), "Volvo", false, FuelTypes.Diesel),
};

Console.WriteLine($"Electric: {CarsRules[FuelTypes.Electric](cars).Count()}");
Console.WriteLine($"Gassoline: {CarsRules[FuelTypes.Gassoline](cars).Count()}");
Console.WriteLine($"Diesel: {CarsRules[FuelTypes.Diesel](cars).Count()}");
Console.WriteLine($"Gassoline & Diesel: {CarsRules[FuelTypes.Gassoline](cars).Union(CarsRules[FuelTypes.Diesel](cars)).Count()}");

Для этого необходимо определить следующие типы:

public enum FuelTypes
{
    Electric, Gassoline, Diesel
}

public sealed class Car : IEquatable<Car>
{
    private readonly Guid _Id;
    private readonly string _Name;
    private readonly bool _IsElectric;
    private readonly FuelTypes _FuelType;

    public Guid Id { get { return _Id; } }
    public string Name { get { return _Name; } }
    public bool IsElectric { get { return _IsElectric; } }
    public FuelTypes FuelType { get { return _FuelType; } }

    public Car(Guid Id, string Name, bool IsElectric, FuelTypes FuelType)
    {
        _Id = Id;
        _Name = Name;
        _IsElectric = IsElectric;
        _FuelType = FuelType;
    }

    public override bool Equals(object obj)
    {
        if (obj is Car)
            return Equals((Car)obj);
        return false;
    }

    public bool Equals(Car obj)
    {
        if (obj == null) return false;
        if (!EqualityComparer<Guid>.Default.Equals(_Id, obj._Id)) return false;
        if (!EqualityComparer<string>.Default.Equals(_Name, obj._Name)) return false;
        if (!EqualityComparer<bool>.Default.Equals(_IsElectric, obj._IsElectric)) return false;
        if (!EqualityComparer<FuelTypes>.Default.Equals(_FuelType, obj._FuelType)) return false;
        return true;
    }

    public override int GetHashCode()
    {
        int hash = 0;
        hash ^= EqualityComparer<Guid>.Default.GetHashCode(_Id);
        hash ^= EqualityComparer<string>.Default.GetHashCode(_Name);
        hash ^= EqualityComparer<bool>.Default.GetHashCode(_IsElectric);
        hash ^= EqualityComparer<FuelTypes>.Default.GetHashCode(_FuelType);
        return hash;
    }

    public override string ToString()
    {
        return String.Format("{{ Id = {0}, Name = {1}, IsElectric = {2}, FuelType = {3} }}", _Id, _Name, _IsElectric, _FuelType);
    }

    public static bool operator ==(Car left, Car right)
    {
        if (object.ReferenceEquals(left, null))
        {
            return object.ReferenceEquals(right, null);
        }

        return left.Equals(right);
    }

    public static bool operator !=(Car left, Car right)
    {
        return !(left == right);
    }
}
0 голосов
/ 07 июня 2018

Вы можете создать словарь количества автомобилей в каждом типе топлива, а затем перечислить, какие типы топлива имеют наибольшее количество, следующим образом ...

var fuelTypeCountDictionary = cars
    .GroupBy(car => car.FuelType)
    .ToDictionary(x => x.Key, x => x.Count());
var max = fuelTypeCountDictionary.Values.Max();
var maxFuelTypes = fuelTypeCountDictionary.Where(x => x.Value == max).Select(x => x.Key);
string mostUsedFuelTypes = string.Join(", ", maxFuelTypes);
Console.WriteLine(mostUsedFuelTypes);

Для приведенных в качестве примера данных это будетна консоли отображается только «Gassoline».

Если бы была привязка, например, 2 автомобиля, использующих бензин, и 2 машины, использующие дизельное топливо, это отобразилось бы на консоли «Gassoline, Diesel».

PS«Gassoline» должен иметь только одну «s».

0 голосов
/ 08 июня 2018

Я понял, как вызвать делегат Func в моем словаре CarRules и передать ему список объектов Car.Если кому-то еще нужно smtg, как это, то, как я сделал это, например, чтобы выяснить, является ли автомобиль электрическим.

int countElectric = CarsRules[FueldType.Electric].Invoke(cars);

Например, выше будет вызываться делегат Func CountElectric, который принимает список автомобилей и возвращаетint.

Используя это, должно быть легко выяснить, какие автомобили чаще всего присутствуют в списке

0 голосов
/ 07 июня 2018
var mostCommonFuelType =
    cars
        .GroupBy(car => car.FuelType)
        .OrderBy(carsByFuelType => carsByFuelType.Count())
        .Select(carsByFuelType => carsByFuelType.Key
        .FirstOrDefault();

Если вам нужно пользовательское правило, просто заставьте правило выбрать ключ для использования в его группировках.Если они не являются взаимоисключающими, в этом случае вам также необходимо использовать SelectMany и возвращать пары ключ и значение.

...