回答:
bool isSubset = !t2.Except(t1).Any();
セットを使用する場合は、ListではなくHashSetを使用してください。次に、単純にIsSubsetOf()を使用できます
HashSet<double> t1 = new HashSet<double>{1,3,5};
HashSet<double> t2 = new HashSet<double>{1,5};
bool isSubset = t2.IsSubsetOf(t1);
LINQを使用していません。:-(
リストを使用する必要がある場合、@ Jaredのソリューションは、存在する繰り返し要素を削除する必要があるという警告とともに機能します。
あなたがいる場合は、ユニットテストをあなたにも利用できるCollectionAssert.IsSubsetOfの方法を:
CollectionAssert.IsSubsetOf(subset, superset);
上記の場合、これは次のことを意味します。
CollectionAssert.IsSubsetOf(t2, t1);
これは、ここに掲載されている他のソリューション、特にトップソリューションよりもはるかに効率的なソリューションです。
bool isSubset = t2.All(elem => t1.Contains(elem));
t1にないt2の単一の要素を見つけることができる場合、t2はt1のサブセットではないことがわかります。この方法の利点は、.Exceptまたは.Intersectを使用するソリューションとは異なり、追加のスペースを割り当てることなく、すべてがインプレースで実行されることです。さらに、このソリューションは、サブセット条件に違反する要素が1つ検出されるとすぐに中断し、他の要素は検索を続行します。以下は、最適な長い形式のソリューションです。これは、私のテストでは、上記の省略形のソリューションよりもわずかに高速です。
bool isSubset = true;
foreach (var element in t2) {
if (!t1.Contains(element)) {
isSubset = false;
break;
}
}
私はすべてのソリューションの基本的なパフォーマンス分析を行いましたが、結果は劇的です。これら2つのソリューションは、.Except()および.Intersect()ソリューションよりも約100倍高速で、追加のメモリを使用しません。
!t2.Except(t1).Any()
。Linqは前向きに取り組んでいます。少なくとも1つの要素がAny()
あるIEnumerable
かどうかを尋ねています。このシナリオでt2.Except(t1)
は、t2
にはない最初の要素のみが出力されt1
ます。の最初の要素t2
が含まれt1
ていない場合、最も早く終了します。すべての要素t2
が含まれt1
ている場合、最も長く実行されます。
t1={1,2,3,...9999}
およびを使用するとt2={9999,9998,99997...9000}
、次の測定値が得られることがわかりました!t2.Except(t1).Any(): 1ms -> t2.All(e => t1.Contains(e)): 702ms
。そして、それは範囲が大きくなるほど悪くなります。
t2.Except (t1)
はIEnumerable
notを返しCollection
ます。あなたは、たとえば、その上に完全で繰り返す場合にのみ可能な項目のすべてを放出するToArray ()
か、ToList ()
または使用foreach
中を壊すことなく。linq遅延実行を検索して、その概念の詳細を読んでください。
t2={1,2,3,4,5,6,7,8}
t1={2,4,6,8}
t2.Except(t1)
=> t2の最初の要素= 1 => 1とt1の差は1です({2,4,6,8}に対してチェックされます)=> Except()
最初の要素1を発行します=> Any()
要素を取得します=> Any()
結果はtrue => t2の要素のチェックは行われません。
@Cameronおよび@Neilからの回答に基づいて、Enumerableクラスと同じ用語を使用する拡張メソッドを作成しました。
/// <summary>
/// Determines whether a sequence contains the specified elements by using the default equality comparer.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">A sequence in which to locate the values.</param>
/// <param name="values">The values to locate in the sequence.</param>
/// <returns>true if the source sequence contains elements that have the specified values; otherwise, false.</returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> values)
{
return !values.Except(source).Any();
}
これを試して
static bool IsSubSet<A>(A[] set, A[] toCheck) {
return set.Length == (toCheck.Intersect(set)).Count();
}
ここでの考え方は、Intersectは両方の配列にある値のみを返すということです。この時点で、結果セットの長さが元のセットと同じである場合、「セット」のすべての要素も「チェック」にあるため、「セット」は「toCheck」のサブセットになります。
注:「セット」に重複がある場合、私のソリューションは機能しません。他の人の票を盗みたくないので変更しません。
ヒント:キャメロンの回答に投票しました。