2017-09-23 13 views
1

私はLinqを初めて使用していて、それに精通しています。私は重複を見つけるために以下のlinqクエリを持っており、それは完全に以下のように動作します:LinqをContainsで使用するとエラーが発生する

// "MergedName"は照会して重複する名前を見つけるデータ列です。

var duplicates = result.AsEnumerable() 
      `.Select(dr => dr.Field<string("MergedName").Replace("'", "''")) 
      .GroupBy(x => x) 
      .Where(g => g.Count() > 1) 
      .Select(g => g.Key) 
      .ToList(); 

    foreach (string duplicate in duplicates.ToArray()) 
      { 
       // Logic to keep one and delete another duplicate. 
      } 

ここで、同じ名前の「MergedName」で類似名を探したいとします。ジョン・スミスとジョン・スミス・ジュニア 私は.Where句で何かを書きましたが、何かが私の構文

var duplicates = result.AsEnumerable() 
       .Select(dr => dr.Field<string>("MergedName").Replace("'", "''")) 
       .Where(C => C.Field<string>("MergedName").ToLower().IndexOf(C.Field<string>("MergedName").ToLower().Trim()) != 1) 
       .Select(g => g.Key) 
       .ToList(); 

foreach (string duplicate in duplicates.ToArray()) 
      { 
       // Logic to keep one and delete another duplicate. 
      } 

エラーと間違っている: - 「文字列 『フィールド』の定義が含まれていないステートメントはどこに例のために そして、最高の拡張メソッドのオーバーロード「System.Data.DatarowExtensions.Fieldは、いくつかの無効な引数」を有している。

あなたはこのコード?または、私が含まれている使用して、類似した名前を見つけることができる他の方法で私を助けてください。

答えて

0

あなたが元のコレクションの種類を投稿することなく言うことは難しいしかし、問題はあなたのエラーメッセージに明記されているものと正確に思われます。

LINQは反復手順で動作し、Select(dr => dr.Field<string>("MergedName").Replace("'", "''"))を呼び出した後、次のexpresionは文字列のコレクションで動作します。そして、文字列型

には何の方法.Fieldに私はあなたがいないがあるので、あなたも、そうSelect(g => g.Key)文句を言わない仕事を2番目の文で任意のグループ化を行っていないC.ToLower()

にあなたのwhere句でC.Field<string>("MergedName").ToLower()を簡素化しようとすることができそこに推測しますString型のKeyプロパティ。

これは構文のみを扱うため、Where句はかなり変わっています。各文字列をそれ自身と比較しています。

あなただけの最後の文の任意の部分に独自の条件を入れて

var names = result.AsEnumerable() 
      .Select(dr => dr.Field<string("MergedName").Replace("'", "''").ToLower().Trim()) 
      .ToList(); //ToList not necessary here, but could prevent multiple executions of the expresion 


var duplicates = names.Where(n => names.Any(m => n.IndexOf(m) != -1)) //quadratic complexity 
      .ToList(); 

ような何かを試みることができる、あなたはそこに二つの文字列mnを持っている、しかし、あなたが望むそれらを比較することができます。
これは間違いなくあなたの問題の最高のパフォーマンスを発揮する解決策ではありませんが、あなたのquestinonのようにLINQを使用しています。明確化した後

:この条件は、あなたの質問に1、ないあなたのコメントの1に基づいています

dr.Field<string>("MergedName").Replace("'", "''").Trim().ToLower().IndexOf(dr2.Field<string>("MergedName").Replace("'", "''").Trim().ToLower()) != -1 

var enumerableResult = result.AsEnumerable(); 
var duplicates = enumerableResult. 
       .Where(dr => enumerableResult.Any(dr2 => /*your comparison*/) 
       .ToList(); 

比較のようなものである可能性があります。しかし、このインラインsytaxを使用する必要はなく、カスタムメソッドを呼び出すことができます。.Any(dr2 => AreSamePerson(dr, dr2))

これは二次的な複雑さがあります。これは、比較するレコードが多い場合にのみ問題になります。

これで、文字列ではなく人物オブジェクトのコレクションが取得されました。重複したコレクションのメンバーを元のメンバーから削除することはできませんが、かなり複雑なロジックが必要です。

ので、最善の解決策があると思われる:(A == B、その後== bの場合)これは問題につながるので、あなたの同等の機能が対称型であることを確認することができます

var duplicates = result.AsEnumerable() 
      .GroupBy(x => x, new PersonyComparer()) 
      .Where(g => g.Count() > 1) 

class PersonyComparer : IEqualityComparer<Person>//person is the type of objects that are in starting collection 
    { 
     public bool Equals(Person b1, Person b2) 
     { 
      if (b2 == null && b1 == null) 
       return true; 
      else if (b1 == null | b2 == null) 
       return false; 


      if(/*your condition*/) 
       return true; 
      else 
       return false; 
     } 

     public int GetHashCode(Person bx) 
     { 
      return 0; //you must make sure that objects that are equal have same hashcode 
     } 
    } 

と推移(もしa == b、b == c、a == c)。さもなければあなたのgrouppingはちょっとねじ込むことができます。

次に、あなたは

foreach(var pgroup in duplicates) 
{ 
    foreach(var person in pgroup .Skip(1)) 
    { 
     //remove from original collection 
    } 
} 
+0

Noxor - 上記のソリューションをありがとうございます、それは正しい方向に役立ちます。私はコレクションの中で同じ人物である2つの名前を持っています: "John Mat Smith"と他のレコードは "John Matthew Smith"です。彼らは同じ人物なので、そのうちの1つを削除します。それは理由です、私はこのリンクにAny.Referredの代わりにContainsを使うことを考えていました: "https://stackoverflow.com/questions/23526773/what-is-the-difference-between-contains-and-any-in- linq "と呼ぶ。似たような名前を最初に照会してリストに入れる方法はありますか?これを早期に明らかにしないことに対する謝罪。 –

+0

オブジェクトの等価メソッドを使用していると思いますので、それをオーバーライドすることができます。同様の名前を持つオブジェクトはtrueを返します。しかし、これは本当に悪い考えのようです。元のコレクションから "複製"レコードを削除したい場合は、文字列だけでなく、重複したオブジェクトのコレクションを保持しようとします。私の答えの編集を参照してください。 – Noxor

+0

あなたは彼らが同じ人であることをどのように知っていますか?あなたが社会保障番号のような他の財産を持っているなら、名前の代わりにグルーピングする方が良いでしょう。 – Noxor

0

は、あなたがこれを望んでいなければならない理由を私は一例でお見せしましょう重複したコレクションのオブジェクトを反復処理することができます。 Noxorが正しく述べたように、実現可能なアプローチはIEqualityComparerを使用することです。しかし今、問題は:等しいものは何ですか?あなたの "平等を含んでいる"あなたは解決できない曖昧さを紹介します。

これを最も基本的な方法で説明しましょう。大文字と小文字の置換を忘れてしまいます。この小さなLinqpadプログラムをご覧ください:

void Main() 
{ 
    var dt = new DataTable(); 
    dt.Columns.Add("MergedName", typeof(string)); 

    dt.Rows.Add("Abby Kelley Foster"); 
    dt.Rows.Add("Kelley Foster"); 
    dt.Rows.Add("Abby Kelley"); 

    dt.AsEnumerable() 
     .Select(r => r.Field<string>("MergedName")) 
     .GroupBy(s => s, new SubstringComparer()) 
     .Select(g => new { g.Key, Count = g.Count() }) 
     .Dump(); 

} 

public class SubstringComparer : IEqualityComparer<string> 
{ 
    public bool Equals(string left, string right) 
    { 
     return left.Contains(right) || right.Contains(left); 
    } 

    public int GetHashCode(string value) 
    { 
     return 0; // Just return 0; There is no hashing mechanism implemented that gives "Abby Kelley Foster" and "Abby Kelley" the same hashcode. 
    } 
} 

出力は何ですか?右:

Abby Kelley Foster 3 

しかし、今度はデータ行の順序を変更してみましょう:

dt.Rows.Add("Abby Kelley"); 
    dt.Rows.Add("Kelley Foster"); 
    dt.Rows.Add("Abby Kelley Foster"); 

あなたは出力を控除することはできますか?ここにあります:

Abby Kelley 1 
Kelley Foster 2 

Abby Kelley Fosterはどうなりましたか?

比較者は最初に、アビ・ケリーのために数えられた最初の2つの不均等な行に遭遇し、ケリー・フォスターとアビー・ケリー・フォスターを比較しました:ビンゴ! "等しい"。ただし、この時点では、最初の行に戻って3番目の行と比較することはありません。

あなたはすべての行を比較し、より洗練された(それでも、単純な)アルゴリズムを試みることができるが、その後あなたはまだ間違っ

Abby Kelley Foster 3 

を取得します。 Abby KelleyとAbby Kelley Fosterだけが同じ人物です。ケリー・フォスターは完全に他の誰かです。つまり、自動化されたアルゴリズムでは解決できません。正確な等価性のみが、単純なアルゴリズムによって決定され得る。

実例を挙げてこの家を打つ:1つのエントリが "Jr."だけであるとします。今すぐ "Jr."という名前のすべての名前重複とみなされます!

+0

Gert Arnold - 同意します。あなたが提供した例は私が遭遇し、私のデータで考えたものです。 –

+0

申し訳ありませんが、あなたはそれを考えているかもしれませんが、私には唯一の結論は、あなたがこのように続けることができないということです。最初の出力(3)が論理的にも正しくないという事実はまだ言及していませんでした。なぜなら、3つ目の出力なしで提供されたときにグループ化されなかった2つの名前が含まれているからです。 –

関連する問題