2012-11-05 49 views
3

我正在使用以下查詢來檢測數據庫中的重複項。使用LINQ/C#查詢檢測「接近重複項」

使用LINQ連接不能很好地工作,因爲X公司也可能被列爲CompanyX,因此我想修改它以檢測「接近重複」。

var results = result 
       .GroupBy(c => new {c.CompanyName}) 
       .Select(g => new CompanyGridViewModel 
        { 
         LeadId = g.First().LeadId, 
         Qty = g.Count(), 
         CompanyName = g.Key.CompanyName, 
        }).ToList(); 

有人可以提出一種方法,我可以更好地控制比較嗎?通過的IEqualityComparer也許(雖然我不完全知道如何將在此情況下工作)

我的主要目標是:

  1. 要列出所有重複的一個子集的第一條記錄(或「near duplicates」)
  2. 要在字段和文本比較上有一定的靈活性,我使用我的重複項。
+0

我認爲這裏的主要問題是你在尋找**重複的**不同排列(例如'公司X','公司X','公司X')或者你在尋找** SOUNDEX ** ? –

+0

@BigM我正在尋找不同的排列。謝謝。 – Nick

回答

1

爲了您明確的「忽略空格」的情況下,你可以簡單地調用

var results = result.GroupBy(c => c.Name.Replace(" ", ""))... 

然而,在你想要的靈活性,一般情況下,我會建立IEqualityComparer<Company>類的庫在你的分組中使用。例如,這也應該這樣做在你的「忽略空間」的情況:

public class CompanyNameIgnoringSpaces : IEqualityComparer<Company> 
{ 
    public bool Equals(Company x, Company y) 
    { 
     return x.Name.Replace(" ", "") == y.Name.Replace(" ", ""); 
    } 

    public int GetHashCode(Company obj) 
    { 
     return obj.Name.Replace(" ", "").GetHashCode(); 
    } 
} 

,您可以使用作爲

var results = result.GroupBy(c => c, new CompanyNameIgnoringSpaces())... 

這是非常簡單的做包含多個字段,或其他定義類似的事情相似性等

請注意,您的「相似」的定義必須是傳遞性的,例如如果你在看整數,你不能將「類似」定義爲「在5以內」,因爲那樣你就會有「0類似於5」和「5類似於10」但不是「0類似於10 」。 (它也必須是自反和對稱的,但這更直接。)

1

好了,因爲你正在尋找不同的排列組合,你可以做這樣的事情:

請記住這是寫在答案,因此它可能不能完全編譯,但你的理念。

var results = result 
    .Where(g => CompanyNamePermutations(g.Key.CompanyName).Contains(g.Key.CompanyName)) 
    .GroupBy(c => new {c.CompanyName}) 
    .Select(g => new CompanyGridViewModel 
     { 
      LeadId = g.First().LeadId, 
      Qty = g.Count(), 
      CompanyName = g.Key.CompanyName, 
     }).ToList(); 

private static List<string> CompanyNamePermutations(string companyName) 
{ 
    // build your permutations here 
    // so to build the one in your example 
    return new List<string> 
    { 
     companyName, 
     string.Join("", companyName.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 
    }; 
} 
1

在這種情況下,您需要定義工作將在哪裏進行,即完全在服務器上,在本地內存中還是在兩者的混合中。

  1. 在本地內存: 在這種情況下,我們有兩條路線,給拉了回來所有的數據,只是做的邏輯在本地內存,或流中的數據和應用邏輯分段。要拉動所有數據只是ToList()ToArray()的基表。爲了流式傳輸數據將建議使用ToLookup()和自定義IEqualityComparer,例如,

    public class CustomEqualityComparer: IEqualityComparer<String> 
    { 
        public bool Equals(String str1, String str2) 
        { 
         //custom logic 
        } 
    
        public int GetHashCode(String str) 
        { 
         // custom logic 
        } 
    } 
    
    //result 
    var results = result.ToLookup(r => r.Name, 
            new CustomEqualityComparer()) 
            .Select(r => ....) 
    
  2. 服務器上完全: 取決於你的供應商,它可以成功地映射。例如。如果我們定義一個近似重複爲一體,具有替代的分隔符人可以做這樣的事情:

    private char[] delimiters = new char[]{' ','-','*'} 
    
    var results = result.GroupBy(r => delimiters.Aggregate(d => r.Replace(d,'')... 
    
  3. 混合物: 在這種情況下,我們分裂兩者之間的工作。除非你提出一個很好的方案,否則這條路線很可能是低效率的。例如。如果我們保持邏輯在本地端,建立分組從一個名稱映射到一個鍵,只是查詢所產生的分組,我們可以做這樣的事情:

    var groupings = result.Select(r => r.Name) 
             //pull into local memory 
             .ToArray() 
             //do local grouping logic... 
    
             //Query results 
    var results = result.GroupBy(r => groupings[r])..... 
    

我個人通常與去第一種選擇,拉小數據集的所有數據和流式傳輸大數據集(根據經驗,我發現每次拉動之間的邏輯流需要比拉動所有數據然後做所有邏輯要長很多)

注意:取決於提供商ToLookup()通常是立即執行,並在建設中分段應用其邏輯。