MillionIntegerList
現在、3つのオプションがあります。最初の2つは、ソートに依存しないという点でより一般的です(最初は指定されていませんでした)。大きなリストがすでにソートされている場合は、3番目が望ましいです。
オプション1
はい、LINQを使用してそれを行うためのより良い方法が間違いなくあります:
var common = MillionIntegerList.Intersect(TwoThousandIntegerList).ToList();
これは、内部でHashSet<int>
ビルドを使用し、その中TwoThousandIntegerList
の各要素を検索します。これは、毎回MillionIntegerList
全体を調べるよりもはるかに効率的です。TwoThousandIntegerList
ブラックリストに載っていないものだけが必要な場合は、次のものが必要です。
var valid = MillionIntegerList.Except(TwoThousandIntegerList).ToList();
結果を1回だけ繰り返す必要がある場合は、ToList
呼び出しを削除する必要があることに注意してください。結果を具体化するために呼び出しを含めたので、結果を複数回安価に調べることができます。Intersect
反復しているだけの場合、またはの戻り値は結果をストリーミングExcept
するだけなので、メモリ使用量の点ではるかに安価になります。
オプション2
LINQ to Objectsの実装の詳細に依存したくないが、それでもハッシュベースのアプローチが必要な場合:
var hashSet = new HashSet<int>(TwoThousandIntegerList);
hashSet.IntersectWith(MillionIntegerList);
// Now use hashSet
オプション3
大きなリストがソートされているという事実を利用するアプローチは間違いなく役に立ちます。
ブラックリストに登録されたリストを最初に並べ替えてもかまわないと仮定すると、次のようなストリーミング(および汎用)実装を作成できます。
// Note: to use this, you'd need to make sure that *both* sequences are sorted.
// You could either sort TwoThousandIntegerList in place, or use LINQ's OrderBy
// method.
public IEnumerable<T> SortedIntersect<T>(this IEnumerable<T> first,
IEnumerable<T> second) where T : IComparable<T>
{
using (var firstIterator = first.GetEnumerator())
{
if (!firstIterator.MoveNext())
{
yield break;
}
using (var secondIterator = second.GetEnumerator())
{
if (!secondIterator.MoveNext())
{
yield break;
}
T firstValue = firstIterator.Current;
T secondValue = secondIterator.Current;
while (true)
{
int comparison = firstValue.CompareTo(secondValue);
if (comparison == 0) // firstValue == secondValue
{
yield return firstValue;
}
else if (comparison < 0) // firstValue < secondValue
{
if (!firstIterator.MoveNext())
{
yield break;
}
firstValue = firstIterator.Current;
}
else // firstValue > secondValue
{
if (!secondIterator.MoveNext())
{
yield break;
}
secondValue = secondIterator.Current;
}
}
}
}
}
IComparer<T>
( Tが比較可能であることに依存する代わりに、必要に応じてをとることができます。)