Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 根据某种标准,从集合中选择最大项_C#_.net 3.5_Extension Methods - Fatal编程技术网

C# 根据某种标准,从集合中选择最大项

C# 根据某种标准,从集合中选择最大项,c#,.net-3.5,extension-methods,C#,.net 3.5,Extension Methods,我是.NET3.5的新手。 我收集了一些物品: IList<Model> models; 我想得到元素,它的名称长度最长。 我试过了 string maxItem=models.Max(model=>model.Name.Length); 但是它当然返回最大长度(我需要一个模型对象)。我知道有一种方法可以使用扩展方法来实现这一点,但我不知道如何实现。不幸的是,没有一种内置的方法来实现这一点-但是编写一个扩展方法来实现这一点非常容易 事实上。。。注意,其中一条评论中有一个更好的实现

我是.NET3.5的新手。 我收集了一些物品:

IList<Model> models;
我想得到元素,它的名称长度最长。 我试过了

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

但是它当然返回最大长度(我需要一个
模型
对象)。我知道有一种方法可以使用扩展方法来实现这一点,但我不知道如何实现。

不幸的是,没有一种内置的方法来实现这一点-但是编写一个扩展方法来实现这一点非常容易

事实上。。。注意,其中一条评论中有一个更好的实现。如果我有时间,我会把它移到体内

编辑:好的,我有一个稍微缩写的版本-它只返回最大元素,使用给定的选择器。也不需要做投影——如果需要的话,以后再做一次。请注意,您可以删除
TValue
上的约束,改用
Comparer.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;
}

我就是这样让它工作的。也许有更好的方法,我不确定:

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

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

也许一个简单迭代列表的方法或过程就足够了

大意是

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 Dim结果为字符串=模型(0)。名称 对于模型中的每个m as模型 如果m.Name.length>result.length,则 结果=m.名称 如果结束 下一个 另一种方法可能是:

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

第一个是长度最长的。这里有另一种方法。有一个版本的
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);
    }
}
公共类可比:i可比
{
私有只读T_值;
私有只读函数比较;
公共可比(电视、职能比较)
{
_值=v;
_比较=比较;
}
公共T值{get{return_值;}}
公共国际比较(可比其他)
{
返回_比较(_值,其他._值);
}
}
那么我们可以说:

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

这涉及到很多额外的分配,但在学术上有点有趣(我认为)。

你可以使用聚合。不需要编写新的扩展方法就可以完成

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);
models.Aggregate(
新的KeyValuePair(),
(a,b)=>(a.Valuea.Key);

这样做的问题是它必须遍历列表两次。这可能非常昂贵(或者需要缓冲数据流)。在可能的情况下,一次完成整个过程会更好。如果您正在编写将在未知上下文中使用的库代码,Jon是对的。如果您了解上下文,就可以知道两次通行证是否昂贵。如果我知道上下文,我会写
d.OrderBy(p=>p.Name.Length).First()
。恐怕models.Max(model=>model.Name.Length)返回int(Length)no-a模型,所以你不能像这样使用它(我指的是最后一行)@agnieszka:这是使用内置的Max方法,而不是我在回答中给出的方法。为了更清楚,您可以将新的名称重命名为“MaxElement”。编辑答案以反映这一点。如果有一个集多次使用比较值,会发生什么情况:即{5,3,5,2}。如果我的理解正确,将返回元素0。但是,是什么使元素0比具有相同值的元素2更特殊呢。。。也许返回一个包含最大值的列表会有所帮助?在我看来,这很蹩脚内置的max函数不是这样自然工作的——这不是更好/更直观吗?内置的Enumerable.max()刚刚被破坏了。如果Max()的编写方法正确,那么它现在所做的可以写成“models.Max(model=>model.Name.Length).Select(model=>model.Name);”。(理由是它同时处理单结果和多结果情况)这需要缓冲整个流,并对基本的O(n)操作进行排序-O(n log n)。换句话说:Max()只需要对第一个元素进行排序,但您的算法需要对所有元素进行排序。有人曾经告诉过我“委托与只有一个成员的接口相同“.你基本上是在Func和IComparable之间建立了一个Adapater。我喜欢。分配成本并不严重:规模不大,GC可以处理清理工作。谢谢。我已经对它进行了更新,使用了通用的IComparable,从而消除了强制转换。关于委托和一个成员接口,请看——他在一个提议的Java语言特性中讨论了这一方面。
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;
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);