C#中与Python的min/max相当的是什么?

5
C#中与以下Python的min/max代码等价的代码是什么:
pairs = [ (2,"dog"), (1, "cat"), (3, "dragon"), (1, "tiger") ]

# Returns the PAIR (not the number) that minimizes on pair[0]
min_pair = min(pairs, key=lambda pair:pair[0])

# this will return (1, 'cat'), NOT 1

看起来C#的Enumerable.Min非常接近。但根据它的MSDN文档,它总是返回最小值(而不是原始对象)。我有什么遗漏吗?

编辑


请注意 - 我不倾向于首先进行排序来实现此目标,因为排序(O(nlogn))的计算量比查找最小值(O(n))更重。
还请注意 - 字典也不是一种理想的方法。它不能处理存在重复键的情况 - (1, "cat") 和 (1, "tiger")。
更重要的是,字典无法处理要处理的项是一个复杂类的情况。例如,在动物对象列表中查找年龄最小的动物,使用年龄作为键:
class Animal
{
  public string name;
  public int age;
}

根据 MSDN 文档,您可以通过设置 TResult 参数来分配结果类型。public static TResult Min<TSource, TResult>,看起来您误解了文档。 - Mayli
1
可能是重复的问题:使用LINQ在字典中找到最小值 - Preet Sangha
1
请参考此链接:https://dev59.com/5nNA5IYBdhLWcg3wjOre - lahsrah
如果您已获得所需信息,请不要忘记将答案标记为已接受... - Pranay Rana
4个回答

3

BCL没有MinBy函数,但是很容易自己编写一个。

public static T MinBy<T, C>(this IEnumerable<T> items, Func<T, C> projection) where C : IComparable<C> {
    return items.Aggregate((acc, e) => projection(acc).CompareTo(projection(e)) <= 0 ? acc : e);
}

你可以选择编写比我更复杂的MinBy函数,以避免重新评估投影。无论如何,一旦你有了MinBy函数,就可以轻松解决问题:

var pairs = new[] {Tuple.Create(2,"dog"), Tuple.Create(1, "cat"), Tuple.Create(3, "dragon"), Tuple.Create(1, "tiger")};
var min_pair = pairs.MinBy(e => e.Item1);

谢谢!这非常接近我所寻找的内容。我有点惊讶,因为C#最初并不支持这样一个有用且常见的操作。 - KFL

0

编辑

var minage = collection.Min( x => x.Age ); //for maxage replace Min by Max
var minAgeAnimals = collection.where(x=> x.age == minage); 
foreach(Animal animal in minAgeAnimals )
   Console.Writeline (  animal.Age.ToString() + " : " + animal.Name); 

在问题编辑之前已经回答过

在 C# 中使用字典对象,然后像这样做可以实现你想要的相同功能。

int minimumKey = touchDictionary.Keys.Min(); 
string value = "";
touchDictionary.TryGetValue(minimumKey, out value))
Console.Writeline ( "min key pair is:-" + minimumKey.ToString() + " : " + value); 

或者

借助于LINQ,编程变得更加容易了。

var dictionary = new Dictionary<int, string>  
                     {{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}  };  

        var maxKey = dictionary.Max(x => x.Key);  
        var minkey = dictionary.Min(x => x.Key);  

1
OP似乎正在寻找具有最小值的对象,而不是该值本身。 - Paul Sasik
1
当您知道键存在(因为您通过Min()获得了它,如果没有键,则会抛出异常),为什么要使用TryGetValue - Ed S.
谢谢回复。请查看更新后的问题,了解为什么不希望使用字典。 - KFL
我还没有给你评分(赞或踩),但我猜测这可能是因为原帖特别说明了它的“关键”部分可以有重复,因此字典对他们来说不适用。 - Kevin Anderson
@Kevin - 这就是为什么我进行了编辑并建议了另一种方法...检查我的编辑...在更新原始问题之前,可以使用字典选项... - Pranay Rana

0

使用

Dictionary<int, string> pairs = new Dictionary<int, string>()
                          { {2,"dog"}, {1, "cat"}, {3, "dragon"} };

var min = pairs.OrderBy(x => x.Key).FirstOrDefault();

OR

int min = pairs.Keys.Min();

Dictionary<int, string> result 
                          = new Dictionary<int, string>() { {min, pairs[min]} };

谢谢。但是排序在计算上更耗时。字典无法处理存在重复键的情况。请查看更新后的问题。 - KFL

0

我会使用

var min = pairs.OrderBy(x => x.FirstValue).FirstOrDefault();

虽然我同意排序比查找最小值更重,但请注意这不是对整个集合进行排序。它是在有序枚举中查找集合中的第一个(或默认)项目 - 这是懒惰迭代。

如果你有

var min = pairs.OrderBy(x => x.FirstValue).ToList().FirstOrDefault();

如果是这样,我同意 - 你正在对你的一组进行排序,然后取第一个。但是LINQ比那更聪明,你不会对集合进行排序。你将从一个可能被排序但尚未执行的集合中取第一个。


除了你提到的Dictionary无法使用复杂集合 - 比如一个Animal列表 - 如果你想按照Animal排序,该怎么办呢?你永远无法按照复杂对象进行排序。相反,你需要使用动物的年龄作为键。字典可以非常容易地做到这一点 - 实际上,字典的键永远不会与字典的值相同,否则它还有什么意义呢?

var animals = new List<Animal>();
// get some animals...

var animalictionary = animals.ToDictionary(a => a.Age);
// assuming the animals have distinct ages, else

var animalLookup = animals.ToLookup(a => a.Age);

foreach (var animalGroup in animalLookup)
{
    var age = animalGroup.Key;
    Console.WriteLine("All these animals are " + age);
    foreach (Animal animal in animalGroup)
    {
        Console.WriteLine(animal.name);
    }
} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接