在 C# 中使用 Dictionary<T, Func<List, bool>> 查找列表中最常见的出现

Using Dictionary<T, Func<List, bool>> to Find Most Common Occurrences In List in C#

假设我的 C# 代码定义如下,我想 return 到我的控制台输出显示列表或汽车中最常见的燃料类型。

// 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"

如果我在上面的列表中有一个平局,例如 2 辆使用汽油的汽车和 2 辆使用柴油的汽车,我如何找到并且 return 两者? 即我想在控制台上同时显示 "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;
}
var mostCommonFuelType =
    cars
        .GroupBy(car => car.FuelType)
        .OrderBy(carsByFuelType => carsByFuelType.Count())
        .Select(carsByFuelType => carsByFuelType.Key
        .FirstOrDefault();

如果您需要自定义规则,只需将规则 select 设为要在其分组中使用的键。除非它们不互斥,否则您还需要使用 SelectMany 和 return 键值对。

您可以创建一个字典,记录每种燃料类型有多少辆汽车,然后列出数量最多的燃料类型,如下所示...

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"。

P.S。 "Gassoline" 应该只有一个 "s".

我想出了如何在我的字典 CarRules 中调用 Func 委托并将其传递给 Car 对象列表。如果其他人需要这样的 smtg,我就是这样做的,例如查找汽车是否是电动的。

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

例如,上面将调用 Func 委托 CountElectric,它接受汽车列表和 returns 一个整数。

使用这个,应该很容易找出列表中最常见的汽车类型

您的结构 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);
    }
}

由于您特别想使用 "CarsRules" 字典作为驱动程序,您可以调整我的其他答案以适应;但首先你需要修复 Count* Func 中的错误。目前他们 return 的答案是 0、1 或 2,无论您在列表中放了多少辆车;而且这不是 returning 你的想法。 例如,如果您在列表中放入一辆汽油车,则 CountElectric 将 return 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 进行更改。

现在字典中的 `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));