按某种标准从集合中选择最大项目

时间:2008-12-21 16:33:00

标签: c# .net-3.5 extension-methods

我是.net 3.5的新手。 我收集了一些物品:

IList<Model> models;

,其中

class Model
{
    public string Name
    {
       get;
       private set;
    }
}

我想获得名称长度最长的元素。 我试过了

string maxItem = models.Max<Model>(model => model.Name.Length);

但它当然会返回最大长度(我需要一个Model个对象)。我知道有一种方法可以使用扩展方法,但我不知道如何。

6 个答案:

答案 0 :(得分:7)

遗憾的是,没有内置的方法可以做到这一点 - 但是编写扩展方法很容易。

实际上是在one of my very first blog posts中......请注意,其中一条评论中有更好的实施方式。如果我有时间,我会把它移到身体里。

编辑:好的,我有一个略有缩写的版本 - 它只是使用给定的选择器返回最大元素。也不需要进行投影 - 如果需要,可以在之后做一次。请注意,您可以删除TValue上的约束并改为使用Comparer<TValue>.Default,或者使用重载来允许将比较指定为另一个参数。

public static TSource MaxBy<TSource, TValue>(this IEnumerable<TSource> source,
                                             Func<TSource, TValue> selector)
    where TValue : IComparable<TValue>
{
    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;

答案 1 :(得分:1)

这是另一种做法。 Max的版本不采用任何标准,并使用IComparable。因此,我们可以提供一种方法来在可比对象中包装任何内容,并使用委托提供比较。

public class Comparable<T> : IComparable<Comparable<T>>
{
    private readonly T _value;
    private readonly Func<T, T, int> _compare;

    public Comparable(T v, Func<T, T, int> compare)
    {
        _value = v;
        _compare = compare;
    }

    public T Value { get { return _value; } }

    public int CompareTo(Comparable<T> other)
    {
        return _compare(_value, other._value);
    }
}

然后我们可以说:

Model maxModel = models.Select(m => new Comparable<Model>(m, (a, b) => a.Name.Length - b.Name.Length)).Max().Value;

这涉及很多额外的分配,但它在学术上很有意思(我认为)。

答案 2 :(得分:0)

这就是我开始工作的方式。也许有更好的方法,我不确定:

    decimal de = d.Max(p => p.Name.Length);
    Model a = d.First(p => p.Name.Length == de);

答案 3 :(得分:0)

使用扩展方法有什么好处吗?

使用列表的简单迭代的方法或过程可能就足够了吗?

的影响
Dim result as string = models(0).Name
for each m as Model in models
  if m.Name.length > result.length then
    result = m.Name
  end if
next

答案 4 :(得分:0)

您可以使用Aggregate。无需编写新的扩展方法即可完成。

models.Aggregate(
                new KeyValuePair<Model, int>(),
                (a, b) => (a.Value < b.Name.Length) ? new KeyValuePair<Model, int>(b, b.Name.Length) : a,
                a => a.Key);

答案 5 :(得分:-1)

另一种方式可能是:

var item = (from m in models select m orderby m.Name.Length descending).FirstOrDefault(); 

第一个将是长度最长的那个。