سؤال

أحاول تنفيذ مقارنات مخصصة على قائمتين من الأوتار واستخدام طريقة .except () LINQ للحصول على تلك التي ليست واحدة من القوائم. السبب في أنني أقوم بمقارنة مخصصة هو أنني بحاجة إلى القيام بمقارنة "غامضة" ، أي يمكن تضمين سلسلة واحدة في قائمة واحدة داخل سلسلة في القائمة الأخرى.

لقد قمت بالمقارنة التالية

public class ItemFuzzyMatchComparer : IEqualityComparer<string>
{
    bool IEqualityComparer<string>.Equals(string x, string y)
    {
        return (x.Contains(y) || y.Contains(x));
    }

    int IEqualityComparer<string>.GetHashCode(string obj)
    {
        if (Object.ReferenceEquals(obj, null))
            return 0;
        return obj.GetHashCode();
    }
}

عندما أقوم بتصحيح ، فإن نقطة التوقف الوحيدة التي تضرب هي في طريقة GethashCode (). يساوي () لم يلمس. أيه أفكار؟

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

المحلول

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

المشكلة في الأساس هي أن مفاهيم التجزئة والمساواة مختلفة تمامًا. لست متأكدًا تمامًا من كيفية تصحيح هذا ، ولكن حتى تقوم بذلك ، فمن المؤكد أنه لن يعمل.

تحتاج إلى التأكد من أن إذا Equals(a, b) يعود صحيح ، ثم GetHashCode(a) == GetHashCode(b). (لا يجب أن يكون العكس صحيحًا - تصادمات التجزئة مقبولة ، على الرغم من أنك من الواضح أنك تريد أن يكون لديك عدد قليل منها قدر الإمكان.)

نصائح أخرى

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

لإظهار المشكلة ، Equals(str, "") يعود صحيح لجميع الأوتار str, ، مما يعني في الأساس أن جميع الأوتار تساوي سلسلة فارغة ونتيجة لذلك ، يجب أن يكون لجميع الأوتار نفس ترميز التجزئة كسلسلة فارغة. لذلك ، الطريقة الوحيدة للتنفيذ IEqualityComparer بشكل صحيح هو العودة دائما نفس رمز التجزئة:

public class ItemFuzzyMatchComparer : IEqualityComparer<string>  { 
  bool IEqualityComparer<string>.Equals(string x, string y)  { 
    return (x.Contains(y) || y.Contains(x)); 
  }  
  int IEqualityComparer<string>.GetHashCode(string obj)  { 
    if (Object.ReferenceEquals(obj, null)) return 0; 
    return 1; 
  } 
}

ثم يمكنك استخدام Except الطريقة وسوف تتصرف بشكل صحيح. المشكلة الوحيدة هي أنك ستحصل على تنفيذ غير فعال (ربما) ، لذلك إذا كنت بحاجة إلى أداء أفضل ، فقد تضطر إلى تنفيذ خاص بك Except. ومع ذلك ، لست متأكدًا تمامًا من مدى عدم الكفاءة في تطبيق LINQ ولست متأكدًا مما إذا كان من الممكن بالفعل أن يكون لديك أي تطبيق فعال لقاعدة المقارنة الخاصة بك.

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

 List<String> listOne = new List<string>(){"hard", "fun", "code", "rocks"};
 List<String> listTwo = new List<string>(){"fund", "ode", "ard"};

 var fuzzyMatchList = from str in listOne
                      from sr2 in listTwo
                      where str.Contains(sr2) || sr2.Contains(str)
                      select str;
 var exceptList = listOne.Except(fuzzyMatchList);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top