リストから空の文字列を削除してから、リストから重複する値を削除する方法


82

テーブルからのいくつかの列値のリストがあるとしましょう。空の文字列と重複する値を削除するにはどうすればよいですか。次のコードを参照してください。

List<string> dtList = dtReportsList.AsEnumerable().Select(dr => dr.Field<string>("column1")).ToList();

これは私が今コーディングしたものですが、Amiramのコードははるかにエレガントなので、ここでその答えを選択します。

DataTable dtReportsList = someclass.GetReportsList();

        if (dtReportsList.Rows.Count > 0)
       { 
           List<string> dtList = dtReportsList.AsEnumerable().Select(dr => dr.Field<string>("column1")).ToList();
           dtList.RemoveAll(x=>x == "");
           dtList = dtList.Distinct().ToList();         

           rcboModule.DataSource = dtList;
           rcboModule.DataBind();               
           rcboModule.Items.Insert(0, new RadComboBoxItem("All", "All"));
       }

RemoveAll()がdtListを変更することを理解します。削除された各要素は、リストが使用する基になる配列内のより高いインデックスの要素を強制的に再配置します。AmiramがWhereメソッドで行うように、単にそれらをスキップする方が高速です。
キースS 2012

回答:


201
dtList  = dtList.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList()

空の文字列と空白はnullのようなものだと思いました。そうでない場合は、IsNullOrEmpty(空白を許可する)、またはを使用できますs != null


たった一つ; Distinct()を使用した重複排除は、メソッドが最悪の場合を想定する必要があるため、比較的非効率的です。
キースS 2012

@KeithSこのデータについて、Distinct最適化を可能にしないアサーションを知っていますか?
Servy 2012

リストを並べ替えてから、並べ替えられたことを表明して、重複排除アルゴリズムを線形にすることができます。私の答えを参照してください。
キースS 2012

9

Amiramの答えは実装されている)(正しい、しかし明確なNされている2操作。リスト内の各アイテムについて、アルゴリズムはそれをすでに処理されたすべての要素と比較し、一意である場合はそれを返し、そうでない場合は無視します。私たちはもっとうまくやれる。

ソートされたリストは、線形時間で重複排除することができます。現在の要素が前の要素と等しい場合は無視し、そうでない場合は返します。並べ替えはNlogNであるため、コレクションを並べ替える必要がある場合でも、いくつかの利点があります。

public static IEnumerable<T> SortAndDedupe<T>(this IEnumerable<T> input)
{
   var toDedupe = input.OrderBy(x=>x);

   T prev;
   foreach(var element in toDedupe)
   {
      if(element == prev) continue;

      yield return element;
      prev = element;      
   }
}

//Usage
dtList  = dtList.Where(s => !string.IsNullOrWhitespace(s)).SortAndDedupe().ToList();

これは同じ要素を返します。それらはソートされているだけです。


すごい。私が間違っていなければ、実際に順序付けを行っている要素を繰り返すことによって。あなたの方法を「怠惰」にする方法を考えられますか?
Amiram Korach 2012

残念ながら、ほとんどの並べ替えでは、コレクション全体の知識を並べ替える必要があります。最後の要素は、返される必要がある最初の要素である可能性があります。したがって、出力の最初の要素を生成するには、入力のすべての要素を評価する必要があります。出力の次の要素を見つけた後に中断される可能性があると私が考えることができる唯一のソートは、SelectionSortバリアントであり、その場合、開始した場所に戻ります。
キースS 2012

その上、私たちの場合、操作全体の結果はリストであり、最初に「熱心な」実行が必要です。IEnumerableとして操作し、実行を延期したい場合は、関数の要点を取得して、IEnumerableを実装する非表示のIteratorクラスに配置できます。
キースS 2012

Distinctハッシュを使用し、O(N ^ 2)よりもO(N)に近い必要があります。出典
Risky Martin

...まあ、私はとんでもないでしょう、それは確かにそうです。System.Linq.Setは、Distinctによって使用される内部ハッシュテーブル実装であり、アイテムのGetHashCode()実装が効率的であり、均等に分散されたハッシュを生成すると仮定すると、O(1)アクセス時間に近くなります(デフォルトの実装ではそうなります) 。ただし、ハッシュテーブルにはメモリの問題があります。.NETの基本的な実装では、intとリンクされたアイテムの2つの配列を使用します。各配列は、せいぜいセット内のアイテムの数に等しく、最悪の場合はその2倍になります。
キースS 2012

1

AmiramKorachソリューションは確かに整頓されています。汎用性のための代替手段があります。

var count = dtList.Count;
// Perform a reverse tracking.
for (var i = count - 1; i > -1; i--)
{
    if (dtList[i]==string.Empty) dtList.RemoveAt(i);
}
// Keep only the unique list items.
dtList = dtList.Distinct().ToList();

4
これは機能しますが、入力コレクションを変更する必要がないため、Where句の方が高速です。リストから要素を削除するときに実行する必要のある「シフト」の数を最小限に抑えていますが、Wh​​ereは入力から何も削除しません。一致しない要素をスキップするだけです。
キースS 2012

0

Amiram Korachのソリューションを簡素化するには:

dtList.RemoveAll(s => string.IsNullOrWhiteSpace(s))

Distinct()またはToList()を使用する必要はありません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.