在列表中查找具有相同ID的最小值

时间:2015-05-08 09:07:25

标签: c# lambda

我有一个对象列表,其结构与此类似: Id,OperationId,Prop1,Prop2,...

我必须从列表中删除所有具有相同Id但具有OperationId的Max值的对象。 例如,我有这个列表的实例:

new List<MyObject>
{
    new MyObject() { Id = 1, OperationId = 1, Prop1, Prop2, ... },
    new MyObject() { Id = 1, OperationId = 2, Prop1, Prop2, ... },
    new MyObject() { Id = 2, OperationId = 1, Prop1, Prop2, ... },
    new MyObject() { Id = 2, OperationId = 2, Prop1, Prop2, ... },
    new MyObject() { Id = 3, OperationId = 2, Prop1, Prop2, ... }
}

结果必须是:

new List<MyObject>
{
    new MyObject() { Id = 1, OperationId = 1, Prop1, Prop2, ... },
    new MyObject() { Id = 2, OperationId = 1, Prop1, Prop2, ... },
    new MyObject() { Id = 3, OperationId = 2, Prop1, Prop2, ... }
}

重要的是:我不必只找到Id和operationId ..结果必须是整个对象!

我尝试过使用Comparer,lambda表达式,Distinct,Grouping和Select,但我还没有找到解决方案......

我该如何解决?

感谢名单, 西蒙娜

4 个答案:

答案 0 :(得分:1)

按Id分组对象,然后从每个组中选择仅具有最大OperationId的对象。但请记住,如果组中只有一个OperationId值,则应返回所有这些对象(minOperationId check):

var result = from o in objects
             group o by o.Id into g
             let maxOperationId = g.Max(o => o.OperationId)
             let minOperationId = g.Min(o => o.OperationId)
             from o in g
             where o.OperationId == minOperationId || o.OperationId != maxOperationId
             select o;

输入

{ Id = 1, OperationId = 1 }
{ Id = 1, OperationId = 2 }
{ Id = 2, OperationId = 1 }
{ Id = 2, OperationId = 2 }
{ Id = 2, OperationId = 3 }
{ Id = 3, OperationId = 1 }
{ Id = 4, OperationId = 1 }
{ Id = 4, OperationId = 1 }

输出

{ Id = 1, OperationId = 1 }
{ Id = 2, OperationId = 1 }
{ Id = 2, OperationId = 2 }
{ Id = 3, OperationId = 1 }
{ Id = 4, OperationId = 1 }
{ Id = 4, OperationId = 1 }

答案 1 :(得分:1)

您可以使用此查询:

myObjects = myObjects
    .Groupby(obj => obj.Id)
    .Select(grp => grp.OrderBy(obj => obj.OperationId).First())
    .ToList();

根据ID删除所有重复项,只剩下最低的OperationId。

答案 2 :(得分:0)

假设您的对象类似于:

 .rating-item{

    border-width:3px;
    border-color:black;
    font-size:150%;
    font-style:bold;

}

.rating-item span{

    border-width: 2px;
    padding:5.5px;
    width:30px;
    border-style: solid;
    border-radius: 50%;
}



    <div class="article-survey-container ">
<div class="article-survey ">

    <div class="selected-text"></div>
    <div class="recorded-message"></div>
    <ul class="ratings">
        <li data-rating="5" class="rating-item" id="muy-dificil-rating"> <span class="fontelico-emo-unhappy "> </span></li>
        <li data-rating="4" class="rating-item" id="dificil-rating">   <span class="fontelico-emo-displeased"> </span></li>
        <li data-rating="3"  class="rating-item"id="normal-rating">   <span class="fontelico-emo-sleep"> </span></li>
        <li data-rating="2"  class="rating-item"id="facil-rating">  <span class="fontelico-emo-happy"> </span></li>
        <li data-rating="1" class="rating-item" id="muy-facil-rating">  <span class="fontelico-emo-grin"> </span></span></li>



    </ul>

    <br>


    <input type="hidden" name="dificultad" id="dificultad" value="">
</div>
</div>
</div>

我们可以使用以下LINQ查询:

public class MyObject
{
    public Int32 Id
    {
        get;
        set;
    }

    public Int32 OperationId
    {
        get;
        set;
    }

    public override string ToString()
    {
        return String.Format("{0}-{1}", this.Id, this.OperationId);
    }
}

以下是用法:

public static IEnumerable<MyObject> RemoveMaxOpIdInIdGroup(List<MyObject> items)
{
    var result = items
        // Group by id
        .GroupBy(item =>
            item.Id)
        // Select each group and max operation id in each group
        .Select(group =>
            new { group, maxOperationId = group.Max(item => item.OperationId) })
        // From each group select the item where opid is not max for this 
        // group or if the group has only one item
        .SelectMany(groupWithMax =>
            groupWithMax
                .group
                .Where(item =>
                    (item.OperationId != groupWithMax.maxOperationId) ||
                    (groupWithMax.group.Count() == 1)));
    return result;
}

答案 3 :(得分:0)

如果您使用MaxBy扩展方法such as the one written by Jon Skeet,则解决方案变得相当简单:

var result = items.GroupBy(item => item.Id).Select(x => x.MaxBy(y => y.OperationId));

(注意,对于具有Id和OperationId的多个项目,选择最大一个项目是任意的。)

示例程序:

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

namespace ConsoleApplication2
{
    class MyObject
    {
        public int Id;
        public int OperationId;
    }

    static class Program
    {
        [STAThread]
        private static void Main()
        {
            IEnumerable<MyObject> items =
                new List<MyObject>
                {
                    new MyObject{Id = 1, OperationId = 1},
                    new MyObject{Id = 1, OperationId = 2},
                    new MyObject{Id = 2, OperationId = 1},
                    new MyObject{Id = 2, OperationId = 2},
                    new MyObject{Id = 3, OperationId = 2}
                };

            var result = items.GroupBy(item => item.Id).Select(x => x.MaxBy(y => y.OperationId));
        }
    }

    public static class EnumerableMaxMinExt
    {
        public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
        {
            return source.MaxBy(selector, Comparer<TKey>.Default);
        }

        public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector, IComparer<TKey> comparer)
        {
            using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
            {
                if (!sourceIterator.MoveNext())
                {
                    throw new InvalidOperationException("Sequence was empty");
                }

                TSource max = sourceIterator.Current;
                TKey maxKey = selector(max);

                while (sourceIterator.MoveNext())
                {
                    TSource candidate = sourceIterator.Current;
                    TKey candidateProjected = selector(candidate);

                    if (comparer.Compare(candidateProjected, maxKey) > 0)
                    {
                        max    = candidate;
                        maxKey = candidateProjected;
                    }
                }

                return max;
            }
        }
    }
}