简体   繁体   English

如何使用LINQ(.NET 4)执行DISTINCT查询?

[英]How do I perform a DISTINCT query using LINQ (.NET 4)?

I have an objectset and want to perform a DISTINCT on the collection. 我有一个对象集,想对集合执行DISTINCT。 The objects returned have about 10 properties each. 返回的对象每个都有大约10个属性。 I want to use the properties so projecting really isn't an option. 我想使用这些属性,因此投影确实不是一种选择。 Of the 10 properties, I only want the DISTINCT applied to two of the fields (DistrictId and ContactId). 在这10个属性中,我只想将DISTINCT应用于两个字段(DistrictId和ContactId)。 How do I do this? 我该怎么做呢?

Since you want only elements that are different in terms of the combination of DistrictId and ContactId you could use GroupBy , then decide how you want to treat the duplicates. 由于只需要在DistrictId和ContactId组合方面不同的元素,因此可以使用GroupBy ,然后决定要如何处理重复项。 Each group in this case represents the items that fall into one distinct combination. 在这种情况下,每个组代表属于一个不同组合的项目。

var results = context.MyCollection
                     .GroupBy( x=> new { x.DistrictId, x.ContactId })
                     .Select(...)

You need to write your own or obtain an implementation of a DistinctBy method that allows you to perform distinction on projected information of the sequence contents while preserving the sequence type. 您需要编写自己的代码或获得DistinctBy方法的实现,该方法允许您在保留序列类型的同时对序列内容的投影信息进行区分。

MoreLINQ provides an implementation of this method . MoreLINQ提供了此方法的实现

We can define an extension method to do a DistinctBy operation on an IEnumerable of T like the following: 我们可以定义一个扩展方法来对T的IEnumerable进行DistinctBy操作,如下所示:

public static class EnumerableExtensions
        {

            /// <summary>
            /// Returns a ienumerable which is distinct by a given property key selector. If a custom equality 
            /// comparer is to be used, pass this in as the comparer. By setting the comparer default to null,
            /// the default comparer is used. 
            /// </summary>
            /// <typeparam name="T">The item type in the ienumerable</typeparam>
            /// <typeparam name="TKey">The type of the key selector (property to disinct elements by)</typeparam>
            /// <param name="coll">The source ienumerable</param>
            /// <param name="keySelector">The key selector, use a member expression in a lambda expression</param>
            /// <param name="comparer">Custom comparer to use, pass in null here to specify that default comparer is used,
            /// however, this is default set to null and not required parameter</param>
            /// <returns></returns>
            public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> coll, Func<T, TKey> keySelector,
                IEqualityComparer<TKey> comparer = null)
            {
                if (coll == null)
                    throw new ArgumentNullException("coll");
                if (keySelector == null)
                    throw new ArgumentNullException("keySelector");

                var result = coll.GroupBy(keySelector, comparer).Select(g => g.First()).ToList();
                return new List<T>(result).AsEnumerable();
            }

        }

The DistinctBy operator can then be tested for example in a simple Console application, where we want to get distinct (Model, Color) tuples ie we want only one car of the combination Model+Color: 然后可以在一个简单的Console应用程序中测试DistinctBy运算符,在该应用程序中我们想要获取不同的(模型,颜色)元组,即我们只需要Model + Color组合中的一辆汽车:

class Program { 课程计划{

    static void Main(string[] args)
    {

        var cars = new []
        {
            new Car {Model = "Audi", Make = "A4", Color = "Black"},
            new Car {Model = "Audi", Make = "A8", Color = "Red"},
            new Car {Model = "Audi", Make = "TT", Color = "Black"},
            new Car {Model = "Volvo", Make = "XC90", Color = "Black"},
            new Car {Model = "Volvo", Make = "S90", Color = "Black"},
            new Car {Model = "Ferrari", Make = "F500", Color = "Yellow"},
            new Car {Model = "Ferrari", Make = "F500", Color = "Red"},
            new Car {Model = "Lada", Make = "Limousine", Color = "Rusty"}
        };

        var groupedCars = cars.DistinctBy(c => new {c.Model, c.Color});


        foreach (var gc in groupedCars)
        {
            Console.WriteLine(gc.ToString()); 
        }

        Console.WriteLine("Press any key to continue ...");
        Console.ReadKey(); 
    }




    // Define other methods and classes here

}

The output is then: 输出为:

Model: Audi, Make: A4, Color: Black
Model: Audi, Make: A8, Color: Red
Model: Volvo, Make: XC90, Color: Black
Model: Ferrari, Make: F500, Color: Yellow
Model: Ferrari, Make: F500, Color: Red
Model: Lada, Make: Limousine, Color: Rusty
Press any key to continue ...

We did not get the item "Audi TT Black" because we already got a black Audi. 我们没有得到“ Audi TT Black”,因为我们已经有一个黑色的奥迪。 We did not get the "Volvo S90 Black" because we already got a black Volvo. 我们没有得到“沃尔沃S90黑色”,因为我们已经有了黑色沃尔沃。 We got both the Ferrari F500 because they got different colors. 我们都得到了法拉利F500,因为它们有不同的颜色。 And sadly, we are stuck with the "Lada Limousine Rusty" since it was the only combination of Model and Color. 遗憾的是,由于“ Lada Limousine Rusty”是模型和颜色的唯一组合,因此我们陷入了困境。

You can try construct an anonymous type for handle this case. 您可以尝试构造匿名类型来处理这种情况。 Suppose your class with 10 properties is Element 假设您的具有10个属性的类是Element

public class Element
    {
        public int FirstProp { get; set; }
        public int SecondProp { get; set; }

       //others 8 cool properties
    }

The query for extracting what you want with an extension method in linq: 使用linq中的扩展方法提取所需内容的查询:

IList<Element> element = new List<Element>();


            var result = new { P1 = element
                                .Select(X => X.FirstProp).Distinct()
                            ,
                               P2 = element
                                    .Select(X => X.SecondProp).Distinct()
                            ,
                                element
                               // do projections here over others 8 properties


            };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM