التحقق مما إذا كانت المصفوفة عبارة عن مجموعة فرعية من مصفوفة أخرى

StackOverflow https://stackoverflow.com/questions/332973

  •  22-07-2019
  •  | 
  •  

سؤال

هل لديك أي فكرة عن كيفية التحقق مما إذا كانت هذه القائمة عبارة عن مجموعة فرعية من قائمة أخرى؟

على وجه التحديد، لقد

List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };

كيف يمكن التحقق من أن t2 هي مجموعة فرعية من t1 باستخدام LINQ؟

هل كانت مفيدة؟

المحلول

bool isSubset = !t2.Except(t1).Any();

نصائح أخرى

استخدم 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. : - (

إذا كنت بحاجة إلى استخدام القوائم، ثم @ حل جاريد يعمل مع التحذير التي سوف تحتاج إلى إزالة أية عناصر المتكررة الموجودة.

إذا كنت كذلك وحدة التجارب يمكنك أيضًا الاستفادة من CollectionAssert.IsSubsetOf طريقة :

CollectionAssert.IsSubsetOf(subset, superset);

في الحالة المذكورة أعلاه هذا يعني:

CollectionAssert.IsSubsetOf(t2, t1);

و @حل كاميرون باعتبارها طريقة التمديد:

public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
    return !a.Except(b).Any();
}

والاستعمال:

bool isSubset = t2.IsSubsetOf(t1);

(وهذا هو مماثل، ولكن ليس تماما نفس نشر واحد على بلوق @ مايكل)

وهذا هو حل أكثر كفاءة بكثير من الآخرين نشرها هنا، وخصوصا حل أفضل:

bool isSubset = t2.All(elem => t1.Contains(elem));

إذا يمكنك العثور على عنصر واحد في T2 غير موجود في T1، ثم أنت تعلم أن T2 ليست مجموعة فرعية من T1. وميزة هذه الطريقة هي أن يتم كل شيء في المكان، دون تخصيص مساحة إضافية، على عكس الحلول باستخدام وفيما عدا أو .Intersect. وعلاوة على ذلك، وهذا الحل هو قادرة على كسر بمجرد أن يجد عنصر واحد ينتهك حالة فرعية، بينما يستمر الآخرون البحث. وفيما يلي مطولا الأمثل من الحل، الذي لا يبعد سوى بشكل هامشي أسرع في بلدي التجارب من الحل اختصار أعلاه.

bool isSubset = true;
foreach (var element in t2) {
    if (!t1.Contains(element)) {
        isSubset = false;
        break;
    }
}

وفعلت بعض تحليل أداء بدائية من كل الحلول، وكانت النتائج جذري. هذه الحلول هما حول 100X أسرع من الحلول لوفيما عدا () و.Intersect ()، واستخدام أي ذاكرة إضافية.

وبناء على اجابات من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();
}
<اقتباس فقرة>   

وهنا نتحقق أنه إذا كان هناك أي الحاضر عنصر في القائمة الطفل (أي t2) التي لم ترد من قبل القائمة الأم (أي t1). إذا لا يكون معمولا ثم القائمة هي مجموعة فرعية من جهة أخرى

وعلى سبيل المثال:

bool isSubset = !(t2.Any(x => !t1.Contains(x)));

وهذه محاولة

static bool IsSubSet<A>(A[] set, A[] toCheck) {
  return set.Length == (toCheck.Intersect(set)).Count();
}

والفكرة هنا هي أن تتقاطع سيعود فقط القيم الموجودة في كل من المصفوفات. عند هذه النقطة إذا كان طول مجموعة الناتج هو نفس المجموعة الأصلية، ثم كل العناصر في "مجموعة" أيضا في "الاختيار"، وبالتالي "مجموعة" هي مجموعة فرعية من "toCheck"

ملحوظة: بلدي الحل لا تعمل إذا "مجموعة" لديها التكرارات. أنا لا تغيير ذلك لأنني لا أريد لسرقة الأصوات الآخرين.

وتلميح: أنا صوت لإجابة كاميرون.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top