জাভাতে দুটি সেট তুলনা করার দ্রুততম উপায় কী?


104

আমি কোডের একটি অংশকে তালিকার উপাদানগুলির সাথে তুলনা করার জন্য অনুকূলিত করার চেষ্টা করছি।

যেমন

public void compare(Set<Record> firstSet, Set<Record> secondSet){
    for(Record firstRecord : firstSet){
        for(Record secondRecord : secondSet){
            // comparing logic
        }
    }
}

সেটে রেকর্ডের সংখ্যা বেশি হবে তা দয়া করে বিবেচনা করুন।

ধন্যবাদ

শেখর


7
তুলনা যুক্তি না জেনে (এবং সংশোধন করে) লুপগুলি অনুকূল করা সম্ভব নয়। আপনি আপনার কোড আরও প্রদর্শন করতে পারেন?
জোসেফএক্স

উত্তর:


163
firstSet.equals(secondSet)

এটি তুলনা যুক্তিতে আপনি যা করতে চান তার উপর নির্ভর করে ... অর্থাত্ যদি আপনি একটি সেটের মধ্যে একটি উপাদান অপরটিতে না পেয়ে খুঁজে পান তবে কি হবে? আপনার পদ্ধতিতে voidরিটার্নের ধরণ রয়েছে তাই আমি ধরে নিই যে আপনি এই পদ্ধতিতে প্রয়োজনীয় কাজটি করবেন।

আপনার যদি প্রয়োজন হয় তবে আরও সূক্ষ্ম নিয়ন্ত্রণ:

if (!firstSet.containsAll(secondSet)) {
  // do something if needs be
}
if (!secondSet.containsAll(firstSet)) {
  // do something if needs be
}

আপনার যদি প্রয়োজন হয় এমন উপাদানগুলি যা একটি সেটে রয়েছে এবং অন্যটি নয়।
সম্পাদনা: set.removeAll(otherSet)একটি বুলিয়ান দেয়, একটি সেট নয়। সরানোর সমস্ত () ব্যবহার করতে, আপনাকে সেটটি অনুলিপি করতে হবে এবং তারপরে এটি ব্যবহার করতে হবে।

Set one = new HashSet<>(firstSet);
Set two = new HashSet<>(secondSet);
one.removeAll(secondSet);
two.removeAll(firstSet);

যদি লিখিত সামগ্রীগুলি oneএবং twoউভয়ই খালি হয় তবে আপনি জানেন যে দুটি সেট সমান ছিল। যদি তা না হয়, তবে আপনি সেই উপাদানগুলি পেয়েছেন যা সেটগুলি অসম করেছে।

আপনি উল্লেখ করেছেন যে রেকর্ডের সংখ্যা বেশি হতে পারে। অন্তর্নিহিত বাস্তবায়ন যদি হয় HashSetতবে প্রতিটি রেকর্ড আনার O(1)সময় হয় তাই আপনি এর চেয়ে সত্যিকারের চেয়ে আরও ভাল কিছু পেতে পারেন না। TreeSetহয় O(log n)


4
রেকর্ড শ্রেণির জন্য সমান () এবং হ্যাশকোড () প্রয়োগ কার্যকরভাবে সমান, যখন সেটে সমান () সমেত প্রার্থনা করা হয়।
ভিনিত রেনল্ডস

4
আমি নিশ্চিত না যে সরানো সমস্ত () উদাহরণ সঠিক কিনা। মুছে ফেলা সমস্ত () অন্য একটি সেট নয়, একটি বুলিয়ান দেয়। সেকেন্ডসেটের উপাদানগুলি আসলে ফার্স্টসেট থেকে সরিয়ে ফেলা হয় এবং যদি কোনও পরিবর্তন করা হয় তবে সত্য ফিরে আসে।
রিচার্ড করফিল্ড

4
সরানোর সমস্ত উদাহরণ এখনও সঠিক নয় কারণ আপনি অনুলিপি তৈরি করেন নি (সেট করুন একটি = ফার্স্টসেট; সেট করুন টু = সেকেন্ডসেট)। আমি অনুলিপি নির্মাণকারী ব্যবহার করব।
মাইকেল রাশ

4
প্রকৃতপক্ষে, ডিফল্ট বাস্তবায়নটি সবচেয়ে খারাপ ক্ষেত্রে equalsদুটি কলের চেয়ে দ্রুত containsAll; আমার উত্তর দেখুন।
স্টিফেন সি

6
আপনার এক সেট করতে হবে = নতুন হ্যাশসেট (ফার্স্টসেট), অন্যথায় ফার্স্টসেট এবং সেকেন্ডসেটের আইটেমগুলি সরানো হবে।
বন্টন 255

61

যদি আপনি কেবল সেটগুলি সমান কিনা তা জানতে চান, তবে equalsপদ্ধতিটি AbstractSetনীচের হিসাবে মোটামুটি কার্যকর করা হবে:

    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Set))
            return false;
        Collection c = (Collection) o;
        if (c.size() != size())
            return false;
        return containsAll(c);
    }

এটি কীভাবে সাধারণ কেসগুলিকে অনুকূল করে তোলে তা নোট করুন:

  • দুটি বস্তু একই
  • অন্য বস্তু মোটেই সেট নয়, এবং is
  • দুটি সেটের মাপ আলাদা।

এর পর, containsAll(...)ফিরে আসবে falseযেমন অন্যান্য সেট যে এই সেট এ নয় একটি উপাদান খুঁজে বের করে যত তাড়াতাড়ি। তবে সমস্ত উপাদান উভয় সেটে উপস্থিত থাকলে, এটির সমস্তটি পরীক্ষা করা দরকার।

সবচেয়ে খারাপ ক্ষেত্রে পারফরম্যান্স ঘটে যখন দুটি সেট সমান হয় তবে একই বস্তু নয়। এই ব্যয়টি সাধারণত O(N)বা O(NlogN)বাস্তবায়নের উপর নির্ভর করে this.containsAll(c)

এবং যদি সেটগুলি বড় হয় এবং কেবলমাত্র উপাদানের ক্ষুদ্র শতাংশে পৃথক হয় তবে আপনি নিকট থেকে খারাপের ক্ষেত্রে পারফরম্যান্স পাবেন।


হালনাগাদ

আপনি যদি কাস্টম সেট বাস্তবায়নে সময় বিনিয়োগ করতে ইচ্ছুক থাকেন তবে এমন একটি পন্থা রয়েছে যা "প্রায় একই" ক্ষেত্রে উন্নতি করতে পারে।

ধারণাটি হ'ল আপনাকে পুরো সেটটির জন্য প্রাক-গণনা এবং একটি হ্যাশ ক্যাশে করা দরকার যাতে আপনি সেটটির বর্তমান হ্যাশকোড মানটি পেতে পারেন O(1)। তারপরে আপনি দুটি সেটের জন্য হ্যাশকোডকে ত্বরণ হিসাবে তুলনা করতে পারেন।

আপনি কীভাবে এর মতো হ্যাশকোড বাস্তবায়ন করতে পারেন? ওয়েল যদি সেট হ্যাশকোড হয়:

  • একটি শূন্য সেট জন্য শূন্য, এবং
  • খালি খালি সেটটির জন্য সমস্ত উপাদানগুলির হ্যাশকোডগুলির এক্সওআর,

তারপরে আপনি যখনই কোনও উপাদান যুক্ত বা সরিয়েছেন তখনই আপনি সস্তাভাবে সেটটির ক্যাশেড হ্যাশকোডটি আপডেট করতে পারবেন। উভয় ক্ষেত্রেই আপনি কেবলমাত্র বর্তমান সেট হ্যাশকোড দিয়ে উপাদানটির হ্যাশকোডটি XOR করেন।

অবশ্যই, এটি ধরে নিয়েছে যে উপাদানগুলি হ্যাশকোডগুলি স্থিতিশীল রয়েছে যখন উপাদানগুলি সেটের সদস্য। এটি ধরেও নিয়েছে যে উপাদানগুলির ক্লাসগুলি হ্যাশকোড ফাংশনটি একটি ভাল স্প্রেড দেয়। কারণ দুটি সেট হ্যাশকোডগুলি একই হ'ল আপনাকে তখনও O(N)সমস্ত উপাদানগুলির তুলনায় ফিরে যেতে হবে।


আপনি এই ধারণাটি আরও খানিকটা এগিয়ে নিতে পারেন ... কমপক্ষে তত্ত্বে।

সতর্কতা - এটি অত্যন্ত অনুমানমূলক। আপনি যদি চান একটি "চিন্তার পরীক্ষা"।

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

এটি আমাদের কী কিনে?

ওয়েল, যদি আমরা ধরে নিই কিছুই প্রচ্ছন্ন হচ্ছে, সম্ভাব্যতা যে কোন দুটি অসম সেট উপাদান একই এন-বিট চেকসাম আছে 2 -n । আর সম্ভাব্যতা 2 অসম সেট একই এন-বিট চেকসাম এছাড়াও 2 আছে -n । সুতরাং আমার ধারণাটি আপনি এই equalsহিসাবে প্রয়োগ করতে পারেন :

    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Set))
            return false;
        Collection c = (Collection) o;
        if (c.size() != size())
            return false;
        return checksums.equals(c.checksums);
    }

উপরের অনুমানের অধীনে, এটি কেবল 2 -N সময়ে একবার আপনাকে ভুল উত্তর দেবে । আপনি যদি এনকে যথেষ্ট বড় করে থাকেন (উদাহরণস্বরূপ 512 বিট) একটি ভুল উত্তরের সম্ভাবনা নগণ্য হয়ে যায় (উদাহরণস্বরূপ প্রায় 10 -150 )।

খারাপ দিকটি হ'ল উপাদানগুলির জন্য ক্রিপ্টো চেকসামগুলি গণনা করা খুব ব্যয়বহুল, বিশেষত বিটের সংখ্যা বৃদ্ধি পাওয়ার কারণে। সুতরাং চেকসামগুলি স্মরণে রাখার জন্য আপনার সত্যিকারের কার্যকর ব্যবস্থা দরকার। এবং এটি সমস্যাযুক্ত হতে পারে।

এবং অন্যান্য খারাপ দিকটি হ'ল ত্রুটির কোনও শূন্যের সম্ভাবনা অগ্রহণযোগ্য হতে পারে , সম্ভাবনা যত কমই হোক না কেন। (তবে যদি তা হয় ... তবে মহাজাগতিক রশ্মি একটি সমালোচনামূলক কিছুকে উল্টিয়ে দেয় এমন ক্ষেত্রে আপনি কীভাবে মোকাবেলা করবেন? বা যদি এটি একই সাথে একই বিটটিকে একটি অপ্রয়োজনীয় সিস্টেমের দু'বারে উল্টায়?)


এটি হওয়া উচিত যদি (চেকসামসডনটম্যাচ (0)) মিথ্যা ফিরে আসে; অন্যথায় doHeavyCompistanceToMakeSureTheSetsReallyMatch (o);
এসকো পাইরাইনেন

অগত্যা। অ-সমতুল্য সেটগুলির জন্য দুটি চেকসামের মিলের সম্ভাবনা যদি যথেষ্ট হয় তবে আমি তুলনামূলকভাবে এড়াতে পারব বলে আমি মনে করি। অংকটি কর.
স্টিফেন সি

17

পেয়ারাতে একটি পদ্ধতি রয়েছে Setsযা এখানে সহায়তা করতে পারে:

public static <E>  boolean equals(Set<? extends E> set1, Set<? extends E> set2){
return Sets.symmetricDifference(set1,set2).isEmpty();
}

5

আপনার https://www.mkyong.com/java/java-how-to-compare-two-sets/ থেকে নিম্নলিখিত সমাধান রয়েছে

public static boolean equals(Set<?> set1, Set<?> set2){

    if(set1 == null || set2 ==null){
        return false;
    }

    if(set1.size() != set2.size()){
        return false;
    }

    return set1.containsAll(set2);
}

অথবা আপনি যদি একক রিটার্নের বিবৃতি ব্যবহার করতে পছন্দ করেন:

public static boolean equals(Set<?> set1, Set<?> set2){

  return set1 != null 
    && set2 != null 
    && set1.size() == set2.size() 
    && set1.containsAll(set2);
}

অথবা কেবলমাত্র (জেডিকে দিয়ে প্রেরণ করা) equals()থেকে পদ্ধতিটি ব্যবহার করুন AbstractSetযা অতিরিক্ত নাল চেক ব্যতীত এখানে সমাধানের মতো প্রায় একই । জাভা -11 সেট ইন্টারফেস
চৈথু নারায়ণ

4

খুব নির্দিষ্ট কেসের ক্ষেত্রে একটি ও (এন) সমাধান রয়েছে যেখানে:

  • সেট উভয় বাছাই করা হয়
  • উভয় একই ক্রম অনুসারে বাছাই করা

নিম্নলিখিত কোডটি ধরে নিয়েছে যে উভয় সেটই তুলনীয় রেকর্ডের ভিত্তিতে। অনুরূপ পদ্ধতিটি তুলনাকারীর উপর ভিত্তি করে তৈরি করা যেতে পারে।

    public class SortedSetComparitor <Foo extends Comparable<Foo>> 
            implements Comparator<SortedSet<Foo>> {

        @Override
        public int compare( SortedSet<Foo> arg0, SortedSet<Foo> arg1 ) {
            Iterator<Foo> otherRecords = arg1.iterator();
            for (Foo thisRecord : arg0) {
                // Shorter sets sort first.
                if (!otherRecords.hasNext()) return 1;
                int comparison = thisRecord.compareTo(otherRecords.next());
                if (comparison != 0) return comparison;
            }
            // Shorter sets sort first
            if (otherRecords.hasNext()) return -1;
            else return 0;
        }
    }

3

আপনি যদি Guavaগ্রন্থাগার ব্যবহার করছেন তবে এটি করা সম্ভব:

        SetView<Record> added = Sets.difference(secondSet, firstSet);
        SetView<Record> removed = Sets.difference(firstSet, secondSet);

এবং তারপরে এগুলির উপর ভিত্তি করে একটি উপসংহার তৈরি করুন।


2

আমি তুলনা করার আগে একটি হ্যাশম্যাপে দ্বিতীয় সেটটি রাখি। এইভাবে আপনি দ্বিতীয় তালিকার সন্ধানের সময়টিকে n (1) এ হ্রাস করবেন। এটার মত:

HashMap<Integer,Record> hm = new HashMap<Integer,Record>(secondSet.size());
int i = 0;
for(Record secondRecord : secondSet){
    hm.put(i,secondRecord);
    i++;
}
for(Record firstRecord : firstSet){
    for(int i=0; i<secondSet.size(); i++){
    //use hm for comparison
    }
}

অথবা আপনি দ্বিতীয় তালিকার জন্য হ্যাশম্যাপের পরিবর্তে অ্যারে ব্যবহার করতে পারেন।
সাহিন হাবসোগলু

এবং, এই সমাধানটি ধরে নেয় যে সেটগুলি বাছাই করা হয়নি।
সাহিন হাবসোগলু

1
public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Set))
            return false;

        Set<String> a = this;
        Set<String> b = o;
        Set<String> thedifference_a_b = new HashSet<String>(a);


        thedifference_a_b.removeAll(b);
        if(thedifference_a_b.isEmpty() == false) return false;

        Set<String> thedifference_b_a = new HashSet<String>(b);
        thedifference_b_a.removeAll(a);

        if(thedifference_b_a.isEmpty() == false) return false;

        return true;
    }

-1

আমি মনে করি সমান পদ্ধতির সাথে পদ্ধতির রেফারেন্স ব্যবহার করা যেতে পারে। আমরা ধরে নিই যে সন্দেহের ছায়া ছাড়াই অবজেক্ট টাইপের নিজস্ব তুলনা পদ্ধতি রয়েছে। সরল এবং সহজ উদাহরণ এখানে,

Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));

Set<String> set2 = new HashSet<>();
set2.addAll(Arrays.asList("hanks","leo","bale"));

Predicate<Set> pred = set::equals;
boolean result = pred.test(set2);
System.out.println(result);   // true

4
এটি বলতে একটি জটিল উপায়set.equals(set2)
অ্যালেক্স
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.