在 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));
假设我的 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));