【问题标题】:LINQ: How to return different field than used by min()LINQ:如何返回与 min() 不同的字段
【发布时间】:2010-12-08 14:40:10
【问题描述】:

我正在使用列表 (masterList) 中的 IEnumerable 字典 (data.Tags)

这是我正在做的一个典型查询(有效):

var tagList = 
    (from data in masterList
    from tag in data.Tags
    where tag.id == 0x10
    select tag).Distinct(new TagComparer());

tag 类具有字段IdValueTranslatedValue。我想根据Id 进行搜索,使用Value 确定哪个是最小值,然后返回TranslatedValue(而不是Value)。

到目前为止,我的所有尝试都会抛出 ArgumentException,例如:

var tagList = 
    (from data in masterList
    from tag in data.Tags
    where tag.id == 0x10
    select new
    {
       tag.Value,
       tag.TranslatedValue
    };
return tagList.Min().TranslatedValue;

有没有优雅的解决方案?

【问题讨论】:

  • .Min() 应该是什么?编译器如何确定它?
  • 如上所述,使用Value 确定哪个是最小值。至于如何,这就是我问的原因:)

标签: c# linq .net-3.5


【解决方案1】:

您可以使用OrderBy 对元素进行升序排序(将最小值放在第一位),Select 获取您的翻译值,然后使用First 获取该最小元素:

var minVal = (from data in masterList 
             from tag in data.Tags
             where tag.id == 0x10
             select tag)
             .Distinct(new TagComparer())
             .OrderBy(t => t.Value) // lowest value will be first in the list
             .First() // take the first element, which is the min
             .TranslatedValue

【讨论】:

    【解决方案2】:

    当我之前遇到这个确切问题时,我的回答比这里的其他人更复杂一些,但它在这些情况下工作得很好并且性能更高一些;开发一个 ObjectWithMin() 扩展方法,该方法将返回包含指定投影最小值的整个对象。这是一个基本算法;它只迭代可枚举一次并线性执行而不是在 nlogn-time 中执行:

    public static T ObjectWithMin<T, TResult>(this IEnumerable<T> elements, Func<T, TResult> projection)
            where TResult : IComparable<TResult>
        {
            if (elements == null) throw new ArgumentNullException("elements", "Sequence is null.");
            if (!elements.Any()) throw new ArgumentException("Sequence contains no elements.");
    
            var seed = elements.Select(t => new { Object = t, Projection = projection(t) }).First();
    
            return elements.Aggregate(seed,
                                      (s, x) =>
                                      projection(x).CompareTo(s.Projection) < 0
                                          ? new {Object = x, Projection = projection(x)}
                                          : s
                ).Object;
        }
    

    用法:

    var tagList = 
        (from data in masterList
        from tag in data.Tags
        where tag.id == 0x10
        select new
        {
           tag.Value,
           tag.TranslatedValue
        };
    return tagList.ObjectWithMin(x=>x.Value).TranslatedValue;
    

    【讨论】:

      【解决方案3】:

      【讨论】:

        【解决方案4】:

        您可以为您的标记类实现IComparable&lt;T&gt;,并将比较基于Value 属性。然后,您可以选择最小标签并从中获取TranslatedValue,而不是选择最小的Value

        一些代码来说明我的意思:

        class tag : IComparable<tag>
        {
            public int Id { get; set; }
        
            public int Value { get; set; }
        
            public int TranslatedValue { get; set; }
        
            public int CompareTo(tag other)
            {
                if (other.Value > this.Value)
                    return -1;
                if (other.Value < this.Value)
                    return 1;
                return 0;
            }
        
            public override string ToString()
            {
                return string.Format("Id:{0}, Value: {1}, TranslatedValue: {2}", Id, Value, TranslatedValue);
            }
        }
        

        这会将您的标记类设置为实现IComparable&lt;T&gt;。要使用它来获取TranslatedValue,它很简单:

        int minTranslatedValue = tags.Min().TranslatedValue;
        

        其中tags 是某种IEnumerable&lt;Tag&gt; 集合。

        【讨论】:

          【解决方案5】:

          您应该能够按一个属性排序,获取第一项,然后获取另一个属性:

          return
            masterList
            .SelectMany(data => data.Tags)
            .Where(tag => tag.id == 0x10)
            .OrderBy(tag => tag.Value)
            .First()
            .TranslatedValue;
          

          【讨论】:

          • 不会 OrderByDescending 将 Max Value 放在第一位(我认为他想要 OrderBy 执行升序)。
          • @Justin Niessner:是的,你是对的。我倒着想。 :P 当然应该是OrderBy
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-04
          • 1970-01-01
          • 2019-04-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多