"তুলনা পদ্ধতিটি এর সাধারণ চুক্তি লঙ্ঘন করে!"


187

কেউ আমাকে সহজ ভাষায় ব্যাখ্যা করতে পারেন, কেন এই কোডটি একটি ব্যতিক্রম উপস্থাপন করে, "তুলনা পদ্ধতিটি এর সাধারণ চুক্তি লঙ্ঘন করে!", এবং আমি কীভাবে এটি সংশোধন করব?

private int compareParents(Foo s1, Foo s2) {
    if (s1.getParent() == s2) return -1;
    if (s2.getParent() == s1) return 1;
    return 0;
}

1
ব্যতিক্রম নাম এবং শ্রেণি কি? এটি কি অবৈধআরগমেন্ট এক্সেপশন? যদি আমার অনুমান করতে হয় তবে আমি ভাবব যে এর s1.getParent().equals(s2)পরিবর্তে আপনার করা উচিত s1.getParent() == s2
ফ্রেইহাইট

এবং ব্যতিক্রম যে পাশাপাশি নিক্ষেপ করা হয়।
ম্যাথু ফারওয়েল

2
আমি জাভা বা জাভা তুলনা এপিআই সম্পর্কে খুব বেশি জানি না, তবে এই তুলনা পদ্ধতিটি ভুল বলে মনে হচ্ছে। ধরা যাক s1এর পিতামাতা s2, এবং s2এর পিতামাতা নয় s1। তারপর compareParents(s1, s2)হয় 0, কিন্তু compareParents(s2, s1)হয় 1। এটা বোঝা যায় না। (
তদ্ব্যতীত

4
এই ত্রুটিটি কেবলমাত্র একটি নির্দিষ্ট গ্রন্থাগার দ্বারা উত্পাদিত হয়েছে বলে মনে হচ্ছে cr.openjdk.java.net/~martin/webrevs/openjdk7/ متاসর্ট
পিটার

জাভাতে, আপনি সমান (একটি বুলিয়ান রিটার্ন) বা তুলনাটো (রিটার্ন -1, 0 বা +1) ব্যবহার করতে পারেন। আপনার ফু ক্লাসে এই ফাংশনগুলি ওভাররাইড করুন এবং তার পরে, আপনি s1.getParent () সমান (এস 2) চেক করতে পারবেন ...
Mualig

উত্তর:


260

আপনার তুলনাকারী অস্থায়ী নয়।

আসুন Aএর পিতামাতা B, এবং Bএর পিতামাতা হতে দিন C। যেহেতু A > Bএবং B > C, তখন অবশ্যই এটি হওয়া উচিত A > C। তবে, যদি আপনার তুলনাকারীটি চালু হয় Aএবং Cএটি শূন্যের অর্থ ফিরে আসেA == C । এটি চুক্তি লঙ্ঘন করে এবং তাই ব্যতিক্রম ছোঁড়ে।

এটি সনাক্ত করার জন্য লাইব্রেরিটি খুব ভাল এবং সঠিকভাবে আচরণ করার চেয়ে আপনাকে জানাতে।

এতে ট্রানজিটিভিটি প্রয়োজনীয়তা পূরণ করার একটি উপায় compareParents()হ'ল getParent()কেবল তাত্ক্ষণিক পূর্বপুরুষের দিকে তাকানোর পরিবর্তে চেইনটিকে অতিক্রম করা ।


3
জাভা 7 এর চালু java.util.Arrays.sort stackoverflow.com/questions/7849539/...
leonbloy

46
লাইব্রেরিটি এটি সনাক্ত করার বিষয়টি দুর্দান্ত। সূর্যের কেউ এমন একজন দৈত্যকে ছুঁড়ে ফেলার প্রাপ্য যা আপনাকে স্বাগতম
কিউস - মনিকা

এই প্রশ্নটিকে একটি রেফারেন্স পোস্ট হিসাবে আরও কার্যকর করতে আপনি এই উত্তরটি কিছুটা সাধারণ করতে পারেন?
বার্নহার্ড বার্কার

1
@ কিউস - যতটা আমি সানকে ভালবাসি, এটি জাভা
in-

1
@ আইসাপির ধিক্কার! ভালো বল ধরা.
কিউস - মনোকিকা

38

আমি এই ত্রুটিটি গুগল করার সময় এটিই পেয়েছিলাম বলে আমার সমস্যাটি ছিল আমার

if (value < other.value)
  return -1;
else if (value >= other.value)
  return 1;
else
  return 0;

value >= other.value(স্পষ্টত) প্রকৃতপক্ষে হওয়া উচিত value > other.value, যাতে আপনি আসলে 0 আসতে পারেন সমান বস্তুর সঙ্গে।


7
আমি যোগ করতে হবে আপনার valueযদি valueকেউ ন্যান হয় (যদি এটি হয় doubleবা হয় float) তবে এটি ব্যর্থও হবে।
ম্যাথিউউ

22

চুক্তির লঙ্ঘন প্রায়শই এর অর্থ যে তুলনাকারী বস্তুর তুলনা করার সময় সঠিক বা সামঞ্জস্যপূর্ণ মান সরবরাহ করে না। উদাহরণস্বরূপ, আপনি একটি স্ট্রিং তুলনা করতে চান এবং খালি স্ট্রিংগুলি এর সাথে শেষ পর্যন্ত বাছাই করতে বাধ্য করতে পারেন:

if ( one.length() == 0 ) {
    return 1;                   // empty string sorts last
}
if ( two.length() == 0 ) {
    return -1;                  // empty string sorts last                  
}
return one.compareToIgnoreCase( two );

তবে এটি সেই ক্ষেত্রে অগ্রাহ্য করে যেখানে দু'একটি এবং দু'জন খালি রয়েছে - এবং সেই ক্ষেত্রে, ভুল মান ফিরে আসে (একটি ম্যাচ দেখানোর জন্য 0 এর পরিবর্তে 1), এবং তুলনাকারী লঙ্ঘন হিসাবে রিপোর্ট করে। এটি লেখা উচিত ছিল:

if ( one.length() == 0 ) {
    if ( two.length() == 0 ) {
        return 0;               // BOth empty - so indicate
    }
    return 1;                   // empty string sorts last
}
if ( two.length() == 0 ) {
    return -1;                  // empty string sorts last                  
}
return one.compareToIgnoreCase( two );

13

এমনকি যদি আপনার তুলনাটিও তত্ত্বের মধ্যে সংক্রামকতা ধারণ করে তবে কখনও কখনও সূক্ষ্ম বাগগুলি মেস আপ করে দেয় ... যেমন ভাসমান পয়েন্ট গাণিতিক ত্রুটি। এটা আমার সাথে ঘটেছিল. এটি আমার কোড ছিল:

public int compareTo(tfidfContainer compareTfidf) {
    //descending order
    if (this.tfidf > compareTfidf.tfidf)
        return -1;
    else if (this.tfidf < compareTfidf.tfidf)
        return 1;
    else
        return 0;

}   

ট্রানজিটিভ সম্পত্তি স্পষ্টভাবে ধারণ করে, তবে কোনও কারণে আমি বেআইনী আর্গুমেন্টএক্সসেপশন পাচ্ছিলাম। এবং এটি সক্রিয় যে ভাসমান পয়েন্ট পাটিগণিতের ক্ষুদ্র ত্রুটির কারণে, রাউন্ড-অফ ত্রুটিগুলি যেখানে ট্রানজিটিভ সম্পত্তিটি ভেঙে দেয় যেখানে তাদের হওয়া উচিত নয়! সুতরাং আমি কোডটি সত্যিই ক্ষুদ্রতম পার্থক্য 0 বিবেচনা করার জন্য পুনরায় লিখেছিলাম এবং এটি কার্যকর হয়েছে:

public int compareTo(tfidfContainer compareTfidf) {
    //descending order
    if ((this.tfidf - compareTfidf.tfidf) < .000000001)
        return 0;
    if (this.tfidf > compareTfidf.tfidf)
        return -1;
    else if (this.tfidf < compareTfidf.tfidf)
        return 1;
    return 0;
}   

2
এটি সহায়ক ছিল! আমার কোডটি যৌক্তিকভাবে ঠিক ছিল তবে যথার্থ সমস্যার কারণে একটি ত্রুটি হয়েছিল।
জেএসং

6

আমাদের ক্ষেত্রে এই ত্রুটিটি পেয়েছিল কারণ আমরা ঘটনাক্রমে এস 1 এবং এস 2 এর তুলনার ক্রমটি উল্টিয়ে দিয়েছি। সুতরাং এটি জন্য নজর রাখুন। এটি নীচের চেয়ে স্পষ্টতই জটিল ছিল তবে এটি একটি চিত্র:

s1 == s2   
    return 0;
s2 > s1 
    return 1;
s1 < s2 
    return -1;

3

জাভা কঠোর অর্থে ধারাবাহিকতা পরীক্ষা করে না, কেবল যদি তা গুরুতর সমস্যায় চলে আসে তবে আপনাকে অবহিত করে। এছাড়াও এটি আপনাকে ত্রুটি থেকে খুব বেশি তথ্য দেয় না।

আমার সর্টারে যা ঘটছে তা নিয়ে আমি হতবাক হয়েছি এবং কঠোর ধারাবাহিকতা চেকার তৈরি করেছি, সম্ভবত এটি আপনাকে সহায়তা করবে:

/**
 * @param dailyReports
 * @param comparator
 */
public static <T> void checkConsitency(final List<T> dailyReports, final Comparator<T> comparator) {
  final Map<T, List<T>> objectMapSmallerOnes = new HashMap<T, List<T>>();

  iterateDistinctPairs(dailyReports.iterator(), new IPairIteratorCallback<T>() {
    /**
     * @param o1
     * @param o2
     */
    @Override
    public void pair(T o1, T o2) {
      final int diff = comparator.compare(o1, o2);
      if (diff < Compare.EQUAL) {
        checkConsistency(objectMapSmallerOnes, o1, o2);
        getListSafely(objectMapSmallerOnes, o2).add(o1);
      } else if (Compare.EQUAL < diff) {
        checkConsistency(objectMapSmallerOnes, o2, o1);
        getListSafely(objectMapSmallerOnes, o1).add(o2);
      } else {
        throw new IllegalStateException("Equals not expected?");
      }
    }
  });
}

/**
 * @param objectMapSmallerOnes
 * @param o1
 * @param o2
 */
static <T> void checkConsistency(final Map<T, List<T>> objectMapSmallerOnes, T o1, T o2) {
  final List<T> smallerThan = objectMapSmallerOnes.get(o1);

  if (smallerThan != null) {
    for (final T o : smallerThan) {
      if (o == o2) {
        throw new IllegalStateException(o2 + "  cannot be smaller than " + o1 + " if it's supposed to be vice versa.");
      }
      checkConsistency(objectMapSmallerOnes, o, o2);
    }
  }
}

/**
 * @param keyMapValues 
 * @param key 
 * @param <Key> 
 * @param <Value> 
 * @return List<Value>
 */ 
public static <Key, Value> List<Value> getListSafely(Map<Key, List<Value>> keyMapValues, Key key) {
  List<Value> values = keyMapValues.get(key);

  if (values == null) {
    keyMapValues.put(key, values = new LinkedList<Value>());
  }

  return values;
}

/**
 * @author Oku
 *
 * @param <T>
 */
public interface IPairIteratorCallback<T> {
  /**
   * @param o1
   * @param o2
   */
  void pair(T o1, T o2);
}

/**
 * 
 * Iterates through each distinct unordered pair formed by the elements of a given iterator
 *
 * @param it
 * @param callback
 */
public static <T> void iterateDistinctPairs(final Iterator<T> it, IPairIteratorCallback<T> callback) {
  List<T> list = Convert.toMinimumArrayList(new Iterable<T>() {

    @Override
    public Iterator<T> iterator() {
      return it;
    }

  });

  for (int outerIndex = 0; outerIndex < list.size() - 1; outerIndex++) {
    for (int innerIndex = outerIndex + 1; innerIndex < list.size(); innerIndex++) {
      callback.pair(list.get(outerIndex), list.get(innerIndex));
    }
  }
}

প্যারামিটারের তালিকা এবং তুলনাকারীর সাথে চেক কনসেশনসি মেটোহডকে কেবল অনুরোধ করুন।
মার্টিন

আপনার কোডটি সংকলন করে না। ক্লাস Compare, Convert(এবং সম্ভাব্য অন্যান্য) সংজ্ঞায়িত করা হয় না। একটি স্ব-অন্তর্ভুক্ত উদাহরণ সহ কোড স্নিপলেট আপডেট করুন।
গিলি

কোডটি আরও পঠনযোগ্য করার জন্য আপনার টাইপ ঠিক করা উচিত checkConsi(s)tencyএবং সমস্ত অনর্থক @paramঘোষণা সরিয়ে ফেলা উচিত ।
রোল্যান্ড ইলিগ

3

আমার ক্ষেত্রে আমি নিম্নলিখিতগুলির মতো কিছু করছি:

if (a.someField == null) {
    return 1;
}

if (b.someField == null) {
    return -1;
}

if (a.someField.equals(b.someField)) {
    return a.someOtherField.compareTo(b.someOtherField);
}

return a.someField.compareTo(b.someField);

যখন আমি.ফোনফিল্ড এবং বি।


3

আমি কোডের এক অংশে এটি দেখেছি যেখানে নাল মানগুলির জন্য প্রায়শই পুনরাবৃত্তি পরীক্ষা করা হত:

if(( A==null ) && ( B==null )
  return +1;//WRONG: two null values should return 0!!!

2

তাহলে compareParents(s1, s2) == -1তারপর compareParents(s2, s1) == 1আশা করা হচ্ছে। আপনার কোড সহ এটি সর্বদা সত্য নয়।

বিশেষত যদি s1.getParent() == s2 && s2.getParent() == s1। এটি সম্ভাব্য সমস্যাগুলির মধ্যে একটি মাত্র।


1

ভিএম কনফিগারেশন সম্পাদনা আমার পক্ষে কাজ করেছে।

-Djava.util.Arrays.useLegacyMergeSort=true

দয়া করে দ্বিগুণ পরীক্ষা করে দেখুন যে ফর্ম্যাটিংয়ে আপনাকে সাহায্য করার আমার প্রচেষ্টা কিছু ভঙ্গ করে নি। -প্রস্তাবিত সমাধানের শুরু সম্পর্কে আমি অনিশ্চিত । এর পরিবর্তে আপনি কোনও এক-আইটেম বুলেট পয়েন্ট তালিকার মতো কিছু করতে চেয়েছিলেন।
ইউনোশচ

2
এছাড়াও দয়া করে বর্ণনা করুন যে এটি বর্ণিত সমস্যার সাথে কীভাবে সহায়তা করে। এটি বর্তমানে কার্যত একটি কোড-উত্তর is
ইউনোশচ

0

আপনি এর মতো অবজেক্টের ডেটা তুলনা করতে পারবেন না: s1.getParent() == s2- এটি বস্তুর রেফারেন্সগুলির সাথে তুলনা করবে। আপনার equals functionFoo ক্লাসের জন্য ওভাররাইড করা উচিত এবং তারপরে তাদের এটির সাথে তুলনা করুনs1.getParent().equals(s2)


না, আসলে আমার মনে হয় ওপি কিছু সাজানোর একটি তালিকা বাছাই করার চেষ্টা করছে এবং রেফারেন্সগুলি আসলে তুলনা করতে চায়।
এডওয়ার্ড ফ্যাল্ক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.