我有一个 IEnumerable 扩展 MaxBy 可以像这样使用
var longest = new [] {"cat", "dogs", "nit" }.MaxBy(x=>x.Count())
应该
"dogs"
实施*强调文本*
public static T MaxBy<T,M>(this IEnumerable<T> This, Func<T,M> selector)
where M : IComparable
{
return This
.Skip(1)
.Aggregate
( new {t=This.First(), m = selector(This.First())}
, (a, t) =>
{
var m = selector(t);
if ( m.CompareTo(a.m) > 0)
{
return new { t, m };
}
else
{
return a;
}
}
, a => a.t);
}
它非常优雅且纯粹是功能性的,但我看到了一个问题。我正在使用作为引用类型并需要垃圾收集的匿名对象。在最坏的情况下,当遍历长度为 NI 的 IEnumerable 时,将进行 N 个内存分配,并且 N 个对象将需要垃圾回收。
我可以编写代码以使用外部可变累加器,但从美学上讲,我更愿意坚持我拥有的模式。
然而,我的担忧在现实中有问题吗?.Net 分代垃圾收集器是否识别出这些对象的寿命很短,一次只有一个并优化正在发生的事情?或者我创建一个自定义值类型( struct )来保存我的累加器而不是使用匿名对象更好。
** 编辑 **
这显然是一种非功能性的方法。
public static T MaxBy<T,M>(this IEnumerable<T> This, Func<T,M> selector)
where M : IComparable
{
var t = This.First();
var max = selector(t);
foreach (var item in This.Skip(1))
{
var m = selector(item);
if ( m.CompareTo(max) > 0)
{
max = m;
t = item;
}
}
return t;
}