按一些标准从集合中选择最大项目
我是.net 3.5的新手。 我有一个项目集合:
IList models;
哪里
class Model { public string Name { get; private set; } }
我想得到名称长度最长的元素。 我试过了
string maxItem = models.Max(model => model.Name.Length);
但它当然会返回最大长度(我需要一个Model
对象)。 我知道有一种方法可以使用扩展方法,但我不知道如何。
这就是我开始工作的方式。 也许有更好的方法,我不确定:
decimal de = d.Max(p => p.Name.Length); Model a = d.First(p => p.Name.Length == de);
不幸的是,没有一种内置的方法可以做到这一点 – 但是编写一个扩展方法来实现它真的很容易。
事实上,这是我的第一篇博客文章之一……请注意,其中一条评论中有更好的实施方式。 如果我有时间,我会把它移到身体里。
编辑:好的,我有一个略有缩写的版本 – 它只使用给定的选择器返回最大元素。 也不需要进行投影 – 如果需要,可以在之后做一次。 请注意,您可以删除TValue
上的约束并使用Comparer
,或者具有允许将比较指定为另一个参数的重载。
public static TSource MaxBy(this IEnumerable source, Func selector) where TValue : IComparable { TValue maxValue = default(TValue); TSource maxElement = default(TSource); bool gotAny = false; foreach (TSource sourceValue in source) { TValue value = selector(sourceValue); if (!gotAny || value.CompareTo(maxValue) > 0) { maxValue = value; maxElement = sourceValue; gotAny = true; } } if (!gotAny) { throw new InvalidOperationException("source is empty"); } return maxElement; }
样本使用:(注意类型推断):
string maxName = models.MaxBy(model => model.Name.Length).Name;
这是另一种方法。 有一个版本的Max
没有标准,并使用IComparable
。 因此,我们可以提供一种方法来包装可比对象中的任何内容,并使用委托提供比较。
public class Comparable : IComparable> { private readonly T _value; private readonly Func _compare; public Comparable(T v, Func compare) { _value = v; _compare = compare; } public T Value { get { return _value; } } public int CompareTo(Comparable other) { return _compare(_value, other._value); } }
然后我们可以说:
Model maxModel = models.Select(m => new Comparable(m, (a, b) => a.Name.Length - b.Name.Length)).Max().Value;
这涉及很多额外的分配,但它在学术上有点有趣(我认为)。
您可以使用Aggregate。 无需编写新的扩展方法即可完成。
models.Aggregate( new KeyValuePair(), (a, b) => (a.Value < b.Name.Length) ? new KeyValuePair(b, b.Name.Length) : a, a => a.Key);
使用扩展方法有什么好处吗?
也许一个简单迭代列表的方法或程序就足够了?
有效的东西
昏暗的结果为string = models(0).Name 对于每个m作为模型中的模型 如果m.Name.length> result.length那么 result = m.Name 万一 下一个
另一种方式可能是:
var item = (from m in models select m orderby m.Name.Length descending).FirstOrDefault();
第一个将是长度最长的一个。