そのリストが別のリストのサブセットであるかどうかを確認する方法について何かアイデアはありますか?
具体的には、
List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };
LINQを使用してt2がt1のサブセットであることを確認するにはどうすればよいですか?
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 のソリューションは、存在する繰り返し要素を削除する必要があるという警告に基づいて機能します。
これは、ここに投稿された他のソリューション、特にトップのソリューションよりもはるかに効率的なソリューションです。
bool isSubset = t2.All(elem => t1.Contains(elem));
t1 にない要素が t2 に 1 つ見つかった場合、t2 は t1 のサブセットではないことがわかります。この方法の利点は、.Except または .Intersect を使用したソリューションとは異なり、追加のスペースを割り当てることなく、すべてインプレースで実行されることです。さらに、このソリューションは、サブセット条件に違反する単一の要素を見つけるとすぐに中断できますが、他の要素は検索を続けます。以下は、ソリューションの最適な長い形式です。私のテストでは、上記の省略形のソリューションよりもわずかに高速です。
bool isSubset = true;
foreach (var element in t2) {
if (!t1.Contains(element)) {
isSubset = false;
break;
}
}
すべてのソリューションの基本的なパフォーマンス分析を行いましたが、結果は劇的です。これら 2 つのソリューションは、.Except() および .Intersect() ソリューションよりも約 100 倍高速であり、追加のメモリを使用しません。
単体テストを行っている場合は、 CollectionAssert.IsSubsetOfメソッドも利用できます。
CollectionAssert.IsSubsetOf(subset, superset);
上記の場合、これは次のことを意味します。
CollectionAssert.IsSubsetOf(t2, t1);
拡張メソッドとしての@Cameronのソリューション:
public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
return !a.Except(b).Any();
}
使用法:
bool isSubset = t2.IsSubsetOf(t1);
(これは似ていますが、@Michael のブログに投稿されたものとまったく同じではありません)
@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は両方の配列にある値のみを返すということです。この時点で、結果のセットの長さが元のセットと同じである場合、「set」のすべての要素も「check」に含まれるため、「set」は「toCheck」のサブセットになります。
注:「set」に重複がある場合、私のソリューションは機能しません。他の人の投票を盗みたくないので、私はそれを変更しません。
ヒント:私はキャメロンの答えに投票しました。