2013-03-21 62 views
0

我有一個包含多條記錄的datarows集合newLinks。這裏是表結構Linq RemoveAll刪除所有項目

LinkSysId | LinkId | Col1 | Col2 
1   1  str str1 
2   1  str5 str4 
3   2  str2 str3 
4   2  str6 str7 

我希望做一個LINQ查詢,這將遍歷集合,只留下頂部1不同的鏈路ID記錄:

LinkSysId | LinkId | Col1 | Col2 
1   1  str str 
3   2  str3 str3 

我試圖做這樣的

newLinks.RemoveAll(rowComp => newLinks.Any(rowDel => 
        rowComp["linkId"].ToString() == rowDel["linkId"].ToString() 
        && rowComp["linkSysId"].ToString() != rowDel["linkSysId"].ToString())); 

但它刪除集合中的所有項目?感謝您的幫助

+0

有趣的是,標題聽起來像一切順利。 – 2013-03-21 13:36:13

+0

@GertArnold我真的很驚訝,因爲它會在迭代整個列表之後進行刪除。我認爲這種邏輯的原因是在迭代中避免萬聖節問題。 – Alex 2013-03-21 13:39:40

+0

請注意,'RemoveAll'根本不是LINQ的一部分。這是'List'的方法,而不是'Enumerable'。 – Servy 2013-03-21 13:55:23

回答

1

「創建新」的方法:

DataTable keepTheseRows = table.AsEnumerable() 
    .GroupBy(r => r.Field<int>("LinkId")) 
    .Select(g => g.First()) // takes the first of each group arbitrarily 
    .CopyToDataTable(); 
+0

謝謝你,你的代碼解決了我的問題 – Alex 2013-03-21 14:03:06

3

有實現DistinctBy(),這是你在找什麼LINQ擴展庫。然而這個小片斷利用,如果相同的項目已添加Add()方法對HashSet的方法返回false的事實:

var foundIds = new HashSet<int>(); 
var FirstLinkId = newLinks.Where(row=>foundIds.Add(row.LinkId)).ToList(); 
+0

這當然是通常實現'Distinct'的方式,只需要一點額外的邏輯就可以有一個單獨的選擇器,一個鍵比較器,參數驗證,等等。這是LINQ'Dictinct'或大多數自定義'DistinctBy'實現的核心。 – Servy 2013-03-21 13:56:47

1

由於Tormod說,最好的辦法是使用DistinctBy()實現。

(尤其是看Tormod的實現,你會看到它實際上是相同的,如下DistinctByImpl()方法,所以這個答案應該被視爲是他的擴展。)

如果使用DistinctBy()時,溶液變得簡單:

var uniques = list.DistinctBy(item => item.LinkId);

一個好的實施DistinctBy()可以在Jon Skeet's MoreLinq library這也是available on NuGet找到。

舉個例子,下面是一個使用MoreLinq的DistinctBy()實現副本的實現。不要使用此代碼 - 使用NuGet下載原始註釋代碼。

using System; 
using System.Linq; 
using System.Collections.Generic; 

namespace Demo 
{ 
    public static class Program 
    { 
     public static void Main(string[] args) 
     { 
      List<Test> list = new List<Test> 
      { 
       new Test(1, 1), 
       new Test(2, 1), 
       new Test(3, 2), 
       new Test(4, 2) 
      }; 

      var uniques = list.DistinctBy(item => item.LinkId); 

      foreach (var item in uniques) 
      { 
       Console.WriteLine(item); 
      } 
     } 
    } 

    public class Test 
    { 
     public Test(int linkSysId, int linkId) 
     { 
      LinkSysId = linkSysId; 
      LinkId = linkId; 
     } 

     public override string ToString() 
     { 
      return string.Format("LinkSysId = {0}, LinkId = {1}", LinkSysId, LinkId); 
     } 

     public int LinkSysId; 
     public int LinkId; 
    } 

    static class EnumerableExt 
    { 
     public static IEnumerable<TSource> DistinctBy<TSource, TKey> 
      (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
     { 
      return source.DistinctBy(keySelector, null); 
     } 

     public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, 
      Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) 
     { 
      if (source == null) throw new ArgumentNullException("source"); 
      if (keySelector == null) throw new ArgumentNullException("keySelector"); 
      return DistinctByImpl(source, keySelector, comparer); 
     } 

     private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source, 
      Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) 
     { 
      var knownKeys = new HashSet<TKey>(comparer); 
      return source.Where(element => knownKeys.Add(keySelector(element))); 
     } 
    } 
}