سؤال

هل هناك أي طريقة في C # .NET 2.0! للجمع بين المتعدد المتعدد؟

دعنا نقول أن لدي التعليمات البرمجية التالية.

List<string> names = new List<string>();
names.Add("Jacob");
names.Add("Emma");
names.Add("Michael");
names.Add("Isabella");
names.Add("Ethan");
names.Add("Emily");

List<string> filteredNames = names.FindAll(StartsWithE);

static bool StartsWithE(string s)
{
    if (s.StartsWith("E"))
    {
        return true;
    }
    else
    {
        return false;
    }
}

هذا يعطيني:

Emma
Ethan
Emily

لذلك هذه الأشياء رائعة جدا، لكنني أعرف أن أرغب في أن أكون قادرا على التصفية باستخدام المسندات المتعددة.

لذلك أريد أن أكون قادرا على قول شيء مثل هذا:

List<string> filteredNames = names.FindAll(StartsWithE OR StartsWithI);

من أجل الحصول على:

Emma
Isabella
Ethan
Emily

كيف يمكنني تحقيق ذلك؟ حاليا أنا فقط تصفية القائمة الكاملة مرتين والجمع بين النتائج بعد ذلك. ولكن لسوء الحظ، هذا لا يكافئ تماما، والأهم من ذلك، فقد تفقد ترتيب الفرز الأصلي، وهو غير مقبول في وضعي.

أحتاج أيضا إلى أن أكون قادرا على التكرار بين أي عدد من المرشحات / المسندات حيث يمكن أن يكون هناك الكثير.

مرة أخرى يجب أن يكون حلا .NET 2.0 لسوء الحظ، لا يمكنني استخدام إصدار أحدث من الإطار

شكرا جزيلا.

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

المحلول

ماذا عن:

public static Predicate<T> Or<T>(params Predicate<T>[] predicates)
{
    return delegate (T item)
    {
        foreach (Predicate<T> predicate in predicates)
        {
            if (predicate(item))
            {
                return true;
            }
        }
        return false;
    };
}

ولإكمال:

public static Predicate<T> And<T>(params Predicate<T>[] predicates)
{
    return delegate (T item)
    {
        foreach (Predicate<T> predicate in predicates)
        {
            if (!predicate(item))
            {
                return false;
            }
        }
        return true;
    };
}

ثم اتصل به مع:

List<string> filteredNames = names.FindAll(Helpers.Or(StartsWithE, StartsWithI));

بديل آخر سيكون استخدام المندوبين المتعددين ثم تقسيمها باستخدام GetInvocationList(), ، ثم تفعل الشيء نفسه. ثم يمكنك القيام به:

List<string> filteredNames = names.FindAll(Helpers.Or(StartsWithE+StartsWithI));

أنا لست معجبا كبيرا من النهج الأخير - إنه يبدو وكأنه قليل من سوء استخدام المتعدد المتعدد.

نصائح أخرى

أعتقد أنك يمكن أن تكتب شيئا مثل هذا:

Func<string, bool> predicate1 = s => s.StartsWith("E");
Func<string, bool> predicate2 = s => s.StartsWith("I");
Func<string, bool> combinedOr = s => (predicate1(s) || predicate2(s));
Func<string, bool> combinedAnd = s => (predicate1(s) && predicate2(s));

... وما إلى ذلك وهلم جرا.

لقد توصلت مؤخرا إلى حل مشابه لهذه المشكلة، والتي قد تكون مفيدة أيضا. قمت بتوسيع طريقة البحث عن القوائم، مما يتيح لي أن تكدس يتأرجح في القوائم كما أحتاج:

public static class ExtensionMethods
{
    public static List<T> FindAll<T> (this List<T> list, List<Predicate<T>> predicates)
    {
        List<T> L = new List<T> ();
        foreach (T item in list)
        {
            bool pass = true;
            foreach (Predicate<T> p in predicates)
            {
                if (!(p (item)))
                {
                    pass = false;
                    break;
                }
            }
            if (pass) L.Add (item);
        }
        return L;
    }
}

تقوم بإرجاع قائمة مع العناصر فقط مطابقة جميع المسندات المعطاة. بالطبع يمكن تغييرها بسهولة أو جميع المسندات بدلا من و. ولكن مع ذلك بمفرده يمكن للمرء أن يتجمع مجموعة كبيرة ومتنوعة جدا من المجموعات المنطقية.

الاستعمال:

{
    List<Predicate<int>> P = new List<Predicate<int>> ();
    P.Add (j => j > 100);
    P.Add (j => j % 5 == 0 || j % 7 == 0);
    P.Add (j => j < 1000);

    List<int> L = new List<int> () { 0, 1, 2, ... 999, 1000 }
    List<int> result = L.FindAll (P);

    // result will contain: 105, 110, 112, 115, 119, 120, ... 994, 995 
}

في .NET 2.0، هناك مندوبون مجهولون أنه يمكنك استخدامه هناك:

List<string> filteredNames = names.FindAll(
   delegate(string s) { return StartsWithE(s) OR StartsWithI(s); }
);

في الواقع، يمكنك استخدامه لاستبدال وظائفك كذلك:

List<string> filteredNames = names.FindAll(
   delegate(string s) { return s.StartsWith("E") || s.StartsWith("I"); }
);

يمكنك إنشاء مسند ثالث أن النتائج داخليا معا. أعتقد أنك يمكن أن تفعل ذلك على الطاير باستخدام تعبير لامدا. شيء من هذا القبيل (هذا ليس تعبيرا لامدا لأنني لست جيدا مع هذا Snytax):

static bool StartsWithEorI(string s)
{
    return StartsWithE(s) || StartsWithI(s);
}

يمكنك التفاف الأسلوب المسند إلى فئة ولديها المنشئ قبول مجموعة من السلاسل لاختبارها من أجل:

class StartsWithPredicate
{
    private string[] _startStrings;
    public StartsWithPredicate(params string[] startStrings)
    {
        _startStrings = startStrings;
    }
    public bool StartsWith(string s)
    {
        foreach (var test in _startStrings)
        {
            if (s.StartsWith(test))
            {
                return true;
            }
        }
        return false;
    }
}

ثم يمكنك إجراء مكالمة مثل هذا:

List<string> filtered = names.FindAll((new StartsWithPredicate("E", "I")).StartsWith);

بهذه الطريقة يمكنك اختبار أي مجموعة من سلاسل المدخلات دون الحاجة إلى تمديد قاعدة التعليمات البرمجية مع اختلافات جديدة لل StartsWith طريقة.

بعد استخدام هذا النمط على نطاق واسع مع طريقة صفيف "Params" أعلاه، كنت مفتونا من خلال التعلم مؤخرا عن المندوب المتعدد المتعدد. منذ أن تدعم المندوبون بطبيعتها قائمة (أو متعددة الإرسال المتعدد)، يمكنك تخطي النمط [] ستحتاج إلى استدعاء قائمة GetInvokation على المسند المرفق <>. انظر الى هذا: Multicapt مندوب من النوع FUNC (مع قيمة الإرجاع)؟

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