2011-05-05 24 views
2

我有一个对象集并希望对集合执行DISTINCT。返回的对象每个都有大约10个属性。我想使用这些属性,所以投影真的不是一个选项。在这10个属性中,我只想将DISTINCT应用于两个字段(DistrictId和ContactId)。我该怎么做呢?如何使用LINQ(.NET 4)执行DISTINCT查询?

回答

4

因为只需要在DistrictId和使用ContactID的组合而言是不同元素,你可以使用GroupBy,然后再决定要如何处理重复。在这种情况下,每个组代表属于不同组合的项目。

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

,如果您只希望每个组中的一个使用'Select(g => g.First()) ;' – BrokenGlass 2011-05-05 16:25:47

1

您需要自己编写或获取DistinctBy方法的实现,该方法允许您在保留序列类型的同时对序列内容的投影信息进行区分。

MoreLINQ规定an implementation of this method

+1

...并使用'Tuple.Create(x.DistrictId,x.ContactId)'作为关键选择器 – Nappy 2011-05-05 16:13:24

0

您可以尝试构造一个匿名类型来处理这种情况。 假设你的类10点的属性是元素

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

     //others 8 cool properties 
    } 

在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 


      }; 
0

我们可以定义一个扩展方法上做了一个DistinctBy操作的T IEnumerable的类似如下:

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(); 
      } 

     } 

的DistinctBy操作者然后可以例如在一个简单的控制台应用程序,在这里我们要测试让不同的(型号,颜色)的元组,即我们只想要组合模型+的一台车颜色:

类节目 {

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 

} 

的输出是:

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 ... 

我们因为我们已经有了一辆黑色的奥迪,所以没有拿到“奥迪TT黑色”的物品。我们没有得到“沃尔沃S90黑色”,因为我们已经有了黑色的沃尔沃。我们得到了法拉利F500,因为它们有不同的颜色。可悲的是,由于它是模型和颜色的唯一组合,因此我们坚持使用“Lada Limousine Rusty”。