【问题标题】:What's the C# equivalence of Python's min/maxPython的最小值/最大值的C#等价物是什么
【发布时间】:2012-05-29 15:12:09
【问题描述】:

以下 Python 的最小/最大代码的 C# 等效项是什么:

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 似乎很接近。但是根据its MSDN doc,它总是返回最小化值(不是原始对象)。我错过了什么吗?

编辑


请注意 - 我不倾向于通过首先排序来实现这一点,因为排序 (O(nlogn)) 在计算上比找到最小值 (O(n)) 更重。

另请注意 - 字典也不是理想的方法。它无法处理存在重复键的情况 - (1, "cat") 和 (1, "tiger")。

更重要的是,字典无法处理要处理的项目是复杂类的情况。例如,在动物对象列表中找到最小值,使用年龄作为键:

class Animal
{
  public string name;
  public int age;
}

【问题讨论】:

  • 根据 MSDN 文档,您可以通过设置 TResult 参数来分配结果类型。 public static TResult Min<TSource, TResult>,看来你对文档有误解。
  • 检查已编辑的答案.....
  • 如果你得到你想要的信息,不要忘记将答案标记为已接受......

标签: c# python


【解决方案1】:

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# 最初不支持这样有用且常见的操作。
【解决方案2】:

使用

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

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

int min = pairs.Keys.Min();

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

【讨论】:

  • 谢谢。但是排序在计算上更耗时。字典无法处理存在重复键的情况。查看更新后的问题。
【解决方案3】:

我会用

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

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

如果你有

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

那么我同意 - 您正在对您的配对进行排序,然后拿走第一对。但是 LINQ 比这更聪明,而且您不会对集合进行排序。您将从可能已订购但尚未执行的集合中获取第一个。


除了你关于Dictionary 无法使用复杂集合的观点——比如Animal 的列表——你将如何按Animal 排序?您永远无法按复杂对象排序。相反,您需要使用动物的年龄作为键。 Dictionary 可以很容易地做到这一点——事实上,Dictionary 的键永远不会与 Dictionary 的值相同,否则有什么意义呢?

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);
    }
} 

【讨论】:

    【解决方案4】:

    编辑

    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);  
    

    【讨论】:

    • OP 似乎在寻找具有最小值的对象而不是值本身。
    • 当你知道密钥存在时为什么要使用TryGetValue(因为你通过Min()获得它,如果没有密钥会抛出异常)?
    • 感谢您的回复。请参阅更新后的问题,了解为什么不需要 Dictionary。
    • 我没有给你打分(上或下),但我猜这是因为 OP 明确表示它的“关键”部分可以有重复,因此字典不适用于他们。
    • @Kevin - 那是我编辑并建议了另一种方式...检查我的编辑...字典是更新 OP 问题之前的选项...
    猜你喜欢
    • 2018-06-30
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 2014-05-08
    • 2011-01-24
    • 2012-09-03
    • 1970-01-01
    相关资源
    最近更新 更多