C# 在查找最小值时避免使用幻数
我需要按键在字典列表中找到min。我是这样做的:C# 在查找最小值时避免使用幻数,c#,linq,C#,Linq,我需要按键在字典列表中找到min。我是这样做的: public int GetMin(string key, List<Dictionary<string,int>> db) { if (db==null || db.Count==0) { return 0; } int result = Int32.MaxValue;
public int GetMin(string key, List<Dictionary<string,int>> db)
{
if (db==null || db.Count==0)
{
return 0;
}
int result = Int32.MaxValue;
foreach (var dic in db)
{
if (dic.TryGetValue(key,out int value) && result>value)
{
result = value;
}
}
return result == Int32.MaxValue ? 0 : result;
}
有没有办法做得更好更有效
我也试着用Linq做这个,但是看起来有点难看。也许用linq更容易做到这一点
var result = db.SelectMany(d => d)?.Where(kvp=>kvp.Key==key)?.OrderBy(x=>x.Value).FirstOrDefault().Value;
return result ?? 0;
您可以编写一个函数,在其中可以检查字典中是否有
键
若字典包含键,则从中返回Min
,若不存在,则返回0
实施:
public static int GetMinFromDictionaryList(List<Dictionary<string, int>> parameter, string key)
{
var keyValuePairList = parameter.SelectMany(d => d).Select(x => x.Key);
if (keyValuePairList.Contains(key))
{
return parameter.SelectMany(d => d).Where(x => x.Key == key).ToList().Min(x => x.Value);
}
return 0;
}
public static int GetMinFromDictionaryList(列表参数,字符串键)
{
var-keyValuePairList=parameter.SelectMany(d=>d).Select(x=>x.Key);
if(keyValuePairList.Contains(key))
{
返回参数.SelectMany(d=>d).Where(x=>x.Key==Key).ToList().Min(x=>x.Value);
}
返回0;
}
POC:一种避免使用
Int32.MaxValue
作为基线并避免在未找到结果时返回0
的方法是使用null
,或使用缩写int?
public static int? GetMin(string key, List<Dictionary<string, int>> db)
{
int? result = null;
if (db != null) {
foreach (var dic in db) {
if (dic.TryGetValue(key, out int value) && (result == null || value < result)) {
result = value;
}
}
}
return result;
}
在方法中使用可为null的int仍然很有用,因为它允许我们避免滥用Int32.MaxValue
。现在,Int32.MaxValue
可以是有效的输入和结果
循环没有问题。不是每件事都需要灵巧。如果要使用LINQ,请确保使用Min
重载处理空值。不可为null的变量为空输入引发异常。列举字典的LINQ变体(使用SelectMany
)没有利用快速字典查找的优势,效率低下
public static int? GetMinLINQ(string key, List<Dictionary<string, int>> db)
{
if (db == null) {
return null;
}
return db
.Select(d => (isMatch: d.TryGetValue(key, out int i), result:i))
.Where(x => x.isMatch)
.Select(x => (int?)x.result)
.Min();
}
公共静态int?GetMinLINQ(字符串键,列表数据库)
{
if(db==null){
返回null;
}
返回数据库
.选择(d=>(isMatch:d.TryGetValue(键,out int i),结果:i))
.其中(x=>x.isMatch)
.选择(x=>(int?)x.result)
.Min();
}
它将
TryGetValue
的返回值和out
变量组合成一个值元组。但是得到的方法并不比使用循环的方法短。我不知道问题出在哪里,这应该很简单
请看下面的例子
public static void Main()
{
var db = new List<Dictionary<string, int>>()
{
new Dictionary<string, int>(){ {"a", 1 }, { "b", 5 }, { "c", 3 } },
new Dictionary<string, int>(){ {"d", 5 }, { "b", 3 } },
new Dictionary<string, int>(){ {"a", 2 }, { "c", 2 } },
};
// Result you will get is 1
Console.Write(GetMin(db, "a").ToString());
}
public static int GetMin(List<Dictionary<string, int>> db, string key)
{
return db == null || !db.Any(x=> x.ContainsKey(key)) ? 0 :
db.SelectMany(x=> x).Where(x=> x.Key == key).Select(x=> x.Value).Min();
}
publicstaticvoidmain()
{
var db=新列表()
{
新字典(){“a”,1},{“b”,5},{“c”,3},
新字典(){“d”,5},{“b”,3},
新字典(){“a”,2},{“c”,2},
};
//您将得到的结果是1
Write(GetMin(db,“a”).ToString();
}
公共静态int GetMin(列表数据库,字符串键)
{
返回db==null | |!db.Any(x=>x.ContainsKey(key))?0:
其中(x=>x.Key==Key).Select(x=>x.Value).Min();
}
由于LINQ查询中唯一的问题是在集合为空时计算最小值(未找到匹配的键,因此引发异常),因此在Min()
之前加上
筛选器未返回任何元素时,只需返回0
不需要使用空值或预筛选:
public int GetMin(string key, List<Dictionary<string, int>> db)
{
if (db is null) return 0;
return db.SelectMany(d => d).Where(kvp => kvp.Key == key).DefaultIfEmpty().Min(v => v.Value);
}
public int GetMin(字符串键,列表数据库)
{
如果(db为空)返回0;
返回db.SelectMany(d=>d).Where(kvp=>kvp.Key==Key).DefaultIfEmpty().Min(v=>v.Value);
}
您可以将其作为LINQ方法的一个序列来编写
因此,您有一个字符串键
和一系列类似的字典,每个字典都是一个字典
。您需要字典键等于“key”的最小整数值。如果所有项目都不包含键
,则希望返回零
幸运的是,Dictionary
实现了IEnumerable
,因此您可以使用SelectMany
、Where
、Select
和Aggregate
string key = ...
List<Dictionary<string, int>> myListOfDictionaries = ...
// note: this implements IEnumerable<IEnumerable<KeyValuePair<string, int>>>
// so a sequence of sequences of KeyValuePairs
var smallestIntThatHasKey = myListOfDictionaries
// make one list containing all keyValuePairs
.SelectMany(dictionary => dictionary)
// result: one sequence of KeyValuePairs
// keep only those KeyValuePairs where the Key equals key
.Where(keyValuePair => keyValuePair.Key == key)
如果没有带键的项,则会正确返回零。这也不是一个非常聪明的解决方案:如果您在排序顺序中找到了第一个元素(最小),那么如果您只打算使用第一个元素,为什么还要麻烦对第二个、第三个等元素进行排序呢。更好地使用聚合:
.Select(keyValuePair => keyValuePair.Value)
.Aggregate(0,(minValue, enumeratedValue) =>
(enumeratedValue < minValue) ? enumeratedValue : minValue);
.Select(keyValuePair=>keyValuePair.Value)
.聚合(0,(最小值,枚举值)=>
(enumeratedValue
这将为聚合结果添加零种子。它将只通过一个序列:它将用枚举值检查MimValk并将最小值作为聚合值IDK,如果我考虑使用魔法值。它有一个清晰的名称,从上下文来看它的用途应该相当明显。预期的输出是什么。@Carcigenicate,如果字典包含Int32.MaxValue怎么办?@Prasadelkikikar,在我上面的例子中,如果我们传递“a”,那么结果是1,如果“b”,那么结果是3,如果“e”,那么结果是0,如果“c”,那么linq post是最简单的。如果有字典就容易多了。如果字典中没有具有给定键的值,则会引发异常。@user194076,现在它支持上述注释中提到的条件在函数中创建可空int
result
,并在返回结果时使用空合并运算符,我相信这是多余的。。如果我错了,请详细说明为什么使用int?结果
。您可以直接使用result=0
,并像我在回答中那样返回结果。这取决于您是否希望能够区分结果“未找到匹配”(=null
)和“找到此最小值”。然后使用int?
作为结果类型是合适的。如果您想返回0
,那么int?
在方法内部仍然很有用,可以避免使用Int32.MinValue
。当然,你也可以使用一个单独的bool
标志。这对我来说是正确的方法。许多人忽略了一个事实,即Min
,Max
的可空重载
public int GetMin(string key, List<Dictionary<string, int>> db)
{
if (db is null) return 0;
return db.SelectMany(d => d).Where(kvp => kvp.Key == key).DefaultIfEmpty().Min(v => v.Value);
}
string key = ...
List<Dictionary<string, int>> myListOfDictionaries = ...
// note: this implements IEnumerable<IEnumerable<KeyValuePair<string, int>>>
// so a sequence of sequences of KeyValuePairs
var smallestIntThatHasKey = myListOfDictionaries
// make one list containing all keyValuePairs
.SelectMany(dictionary => dictionary)
// result: one sequence of KeyValuePairs
// keep only those KeyValuePairs where the Key equals key
.Where(keyValuePair => keyValuePair.Key == key)
.Select(keyValuePair => keyValuePair.Value)
.OrderBy(value => value)
.FirstOrDefault();
.Select(keyValuePair => keyValuePair.Value)
.Aggregate(0,(minValue, enumeratedValue) =>
(enumeratedValue < minValue) ? enumeratedValue : minValue);