JavaRush /جاوا بلاگ /Random-SD /جاوا ۾ موازنہ ڪندڙ
Viacheslav
سطح

جاوا ۾ موازنہ ڪندڙ

گروپ ۾ شايع ٿيل
صرف سست ماڻهن جاوا ۾ Comparator ۽ comparison بابت نه لکيو آهي. مان سست نه آهيان - تنهن ڪري مان توهان کان پڇان ٿو ته هڪ وڌيڪ تبديلي سان پيار ۽ احسان ڪريو. مون کي اميد آهي ته اها ضرورت کان وڌيڪ نه هوندي. ۽ ها، هي آرٽيڪل سوال جو جواب آهي: "ڇا توهان ياداشت مان هڪ موازنہ لکي سگهو ٿا؟" اميد اٿم ته هي مضمون پڙهڻ کان پوءِ هرڪو يادگيري مان هڪ موازن لکڻ جي قابل هوندو.
جاوا ۾ موازنہ ڪندڙ - 1
تعارف جاوا هڪ اعتراض تي مبني ٻولي طور سڃاتو وڃي ٿو. نتيجي طور، جاوا ۾ اهو عام آهي ته شين سان هلائڻ لاء. پر جلد يا بعد ۾ شين جي مقابلي جو ڪم ڪجهه اصولن مطابق پيدا ٿئي ٿو. تنهن ڪري، ڏنو ويو آهي: اسان وٽ ڪجهه پيغام آهي، جيڪو پيغام ڪلاس پاران بيان ڪيو ويو آهي:
public static class Message {
    private String message;
    private int id;

    public Message(String message) {
        this.message = message;
        this.id = new Random().nextInt(1000);
    }
    public String getMessage() {
        return message;
    }
    public Integer getId() {
        return id;
    }
    public String toString() {
        return "[" + id + "] " + message;
    }
}
اچو ته هن ڪلاس کي Tutorialspoint java compiler ۾ شامل ڪريون . اچو ته واردات شامل ڪرڻ لاءِ پڻ ياد رکون:
import java.util.Random;
import java.util.ArrayList;
import java.util.List;
مکيه طريقي سان اسان ڪيترائي پيغام ٺاهي سگهنداسين:
public static void main(String[] args){
    List<Message> messages = new ArrayList();
    messages.add(new Message("Hello, World!"));
    messages.add(new Message("Hello, Sun!"));
    System.out.println(messages);
}
اچو ته سوچون ته اسان کي ڇا ڪرڻ گهرجي جيڪڏهن اسان انهن جي مقابلي ڪرڻ چاهيون ٿا؟ مثال طور، اسان id ذريعي ترتيب ڏيڻ چاهيون ٿا. ۽ ترتيب ٺاھڻ لاءِ، توھان کي ڪنھن نه ڪنھن طرح شين جو مقابلو ڪرڻو پوندو ته سمجھڻ لاءِ ته ڪھڙي شئي پوئين آھي (يعني ننڍو) ۽ جيڪو اڳيان آھي (يعني وڏو). اچو ته هڪ ڪلاس سان شروع ڪريون جهڙوڪ java.lang.Object . جيئن ته اسان ڄاڻون ٿا، سڀئي طبقا هن آبجیکٹ ڪلاس مان ورثي طور تي ورثي ۾ آهن. ۽ اهو منطقي آهي، ڇاڪاڻ ته اهو بنيادي طور تي تصور کي ظاهر ڪري ٿو: "هر شي هڪ اعتراض آهي" ۽ سڀني طبقن لاء عام رويي مهيا ڪري ٿي. ۽ هي ڪلاس بيان ڪري ٿو ته هر ڪلاس جا ٻه طريقا آهن: → hashCode hashCode طريقو ڪلاس جي مثال طور اعتراض جي ڪجهه عددي (int) نمائندگي ڏئي ٿو. هن جو ڇا مطلب آهي؟ ان جو مطلب اهو آهي ته جيڪڏهن توهان هڪ طبقي جا ٻه مختلف مثال ٺاهيا، پوء جيئن ته مثال مختلف آهن، انهن جو هيش ڪوڊ مختلف هجڻ گهرجي. اھو اھو آھي جيڪو ھن طريقي جي وضاحت ۾ چوي ٿو: ”جيترو معقول حد تائين عملي آھي، ھيش ڪوڊ جو طريقو ڪلاس Object پاران بيان ڪيو ويو آھي مختلف شين لاءِ ڌار ڌار عدد واپس ڪري ٿو“ اھو آھي، جيڪڏھن اھي ٻه مختلف مثالون آھن، ته پوءِ انھن کي مختلف ھئڻ گھرجي. hashCodes. اهو آهي، هي طريقو اسان جي مقابلي لاء مناسب ناهي. → equals برابري وارو طريقو سوال جو جواب ڏئي ٿو ”آجز برابر آهن“ ۽ هڪ بوليان موٽائي ٿو. ھن طريقي ۾ ڊفالٽ ڪوڊ آھي:
public boolean equals(Object obj) {
    return (this == obj);
}
اهو آهي، ڪنهن شئي تي هن طريقي کي ختم ڪرڻ کان سواء، هي طريقو لازمي طور تي چوي ٿو ته اعتراض جا حوالا ملن ٿا يا نه. هي اسان جي پيغامن لاءِ موزون ناهي، ڇاڪاڻ ته اسان کي اعتراض جي لنڪ ۾ دلچسپي نه آهي، اسان کي پيغام جي سڃاڻپ ۾ دلچسپي آهي. ۽ جيتوڻيڪ اسان برابري واري طريقي کي ختم ڪريون ٿا، وڌ ۾ وڌ اسان حاصل ڪنداسين: "اهي برابر آهن" يا "اهي برابر نه آهن." پر اهو اسان لاء ڪافي نه آهي ته حڪم کي طئي ڪرڻ لاء.

جاوا ۾ Comparator ۽ Comparable

ڇا اسان کي مناسب آهي؟ جيڪڏھن اسين لفظ ”compare“ کي انگريزيءَ ۾ ترجمو ڪري ترجمي ۾ آڻينداسين، تڏھن اسان کي ترجمو ملندو ”compare“. عظيم، پوء اسان کي ڪنهن جي ضرورت آهي جيڪو مقابلو ڪندو. جيڪڏهن توهان هن مقابلي جو مقابلو ڪريو، پوء جيڪو مقابلو ڪري ٿو اهو مقابلو ڪندڙ آهي. اچو ته Java Api کوليون ۽ اتي Comparator ڳوليون . ۽ حقيقت ۾، اتي ھڪڙو انٽرفيس آھي - java.util.Comparator java.util.Comparator ۽ java.lang.Comparable جيئن توھان ڏسي سگھو ٿا، ھڪڙو انٽرفيس آھي. اهو طبقو جيڪو ان کي لاڳو ڪري ٿو اهو چوي ٿو ته "آئون هڪ فنڪشن لاڳو ڪري رهيو آهيان شين جي مقابلي لاءِ." حقيقت ۾ ياد رکڻ لاءِ واحد شيءِ آهي موازنہ ڪندڙ معاهدو، جنهن جو اظهار هن ريت ڪيو ويو آهي:

Comparator возвращает int по следующей схеме: 
  • отрицательный int (первый an object отрицательный, то есть меньше)
  • положительный int (первый an object положительный, хороший, то есть больший)
  • ноль = an objectы равны
هاڻي اچو ته هڪ comparator لکون. اسان کي java.util.Comparator درآمد ڪرڻو پوندو . درآمد ڪرڻ کان پوء، مکيه ۾ هڪ طريقو شامل ڪريو: Comparator<Message> comparator = new Comparator<Message>(); قدرتي طور، اهو ڪم نه ڪندو، ڇاڪاڻ ته Comparator هڪ انٽرفيس آهي. تنهن ڪري، قوس کان پوء اسين گھڙي وارا شامل ڪنداسين { }. انهن بریکٹس ۾ اسان اهو طريقو لکنداسين:
public int compare(Message o1, Message o2) {
    return o1.getId().compareTo(o2.getId());
}
توهان کي اهو لکڻ لاء ياد رکڻ جي ضرورت ناهي. هڪ موازنہ ڪندڙ اهو آهي جيڪو هڪ مقابلي کي انجام ڏئي ٿو، اهو آهي، مقابلو ڪري ٿو. ان سوال جو جواب ڏيڻ لاءِ ته مقابلي واريون شيون ڪهڙي ترتيب ۾ آهن، اسان واپس int. اهو سڀ ڪجهه آهي، اصل ۾. سادو ۽ آساني سان. جيئن ته اسان مثال مان ڏسي سگهون ٿا، Comparator کان علاوه، هڪ ٻيو انٽرفيس آهي - java.lang.Comparable ، جنهن کي لاڳو ڪرڻ لاءِ اسان کي compareTo طريقي جي وضاحت ڪرڻ گهرجي . هي انٽرفيس چوي ٿو ته "هڪ ڪلاس جيڪو هڪ انٽرفيس کي لاڳو ڪري ٿو، ڪلاس جي مثالن جو مقابلو ڪرڻ جي اجازت ڏئي ٿو." مثال طور، Integer جي compareTo تي عمل درآمد هن طرح نظر اچي ٿو:
(x < y) ? -1 : ((x == y) ? 0 : 1)
انهن سڀني انٽرفيس کي ڪيئن ياد ڪجي؟ ڇا لاءِ؟ سڀ ڪجهه انگريزيءَ مان اچي ٿو. Compare - compare ڪرڻ لاءِ، جيڪو compare ڪري ٿو اهو Comparator آهي (جيئن ته رجسٽرار، مثال طور. اهو آهي، جيڪو رجسٽر ڪري ٿو)، ۽ صفت ”مقابلي“ آهي Comparable. خير، ”سانهن سان موازنہ“ ترجمو ڪيو ويو آهي نه رڳو compare سان، پر ان جي مقابلي ۾ پڻ. اهو سادو آهي. جاوا ٻولي انگريزي ڳالهائيندڙ ماڻهن طرفان لکيل هئي، ۽ جاوا ۾ هر شيء کي نالو ڏيڻ ۾ انهن کي صرف انگريزيء جي هدايت ڪئي وئي هئي ۽ نالي ۾ ڪجهه قسم جي منطق هئي. ۽ compareTo طريقو بيان ڪري ٿو ته ڪيئن هڪ طبقي جو مثال ٻين مثالن سان مقابلو ڪيو وڃي. مثال طور، تارن جو لغوي لحاظ سان مقابلو ڪيو ويندو آهي ، ۽ انگن جو مقابلو قدر سان ڪيو ويندو آهي.
جاوا ۾ موازنہ ڪندڙ - 2
جاوا 8 ڪجهه سٺيون تبديليون کڻي آيو. جيڪڏهن اسان ڪمپيريٽر انٽرفيس تي ويجهڙائي سان نظر وجهنداسين ته اسان ڏسنداسين ته ان جي مٿان هڪ تشريح موجود آهي @FunctionalInterface. حقيقت ۾، هي تشريح معلومات لاءِ آهي ۽ مطلب ته هي انٽرفيس ڪم ڪندڙ آهي. هن جو مطلب اهو آهي ته هن انٽرفيس ۾ صرف 1 خلاصو طريقو آهي بغير ڪنهن عمل جي. هي اسان کي ڇا ڏئي ٿو؟ اسان هاڻي هن طرح موازنہ ڪوڊ لکي سگهون ٿا:
Comparator<Message> comparator = (o1, o2) -> o1.getId().compareTo(o2.getId());
قوس ۾ اهو آهي ته اسان متغيرن کي ڪيئن نالو ڏيون ٿا. جاوا پاڻ اهو ڏسندو ڇو ته ... جيڪڏهن صرف هڪ طريقو آهي، پوء اهو واضح آهي ته ان پٽ پيٽرولر جي ضرورت آهي، ڪيترا، ۽ ڪهڙي قسم جا. اڳيون، اسان هڪ تير سان چوندا آهيون ته اسان انهن کي ڪوڊ جي هن حصي ۾ منتقل ڪرڻ چاهيون ٿا. ان کان علاوه، جاوا 8 جي مهرباني، ڊفالٽ طريقا انٽرفيس ۾ ظاهر ٿيا - اهي طريقا آهن جيڪي ظاهر ٿيندا آهن ڊفالٽ (ڊفالٽ طور) جڏهن اسان هڪ انٽرفيس کي لاڳو ڪندا آهيون. انهن مان ڪيترائي آهن Comparator انٽرفيس ۾. مثال طور:
Comparator moreImportant = Comparator.reverseOrder();
Comparator lessImportant = Comparator.naturalOrder();
ھڪڙو ٻيو طريقو آھي جيڪو توھان جو ڪوڊ صاف ڪندو. اچو ته مٿي ڏنل مثال تي نظر رکون، جتي اسان اسان جي مقابلي کي بيان ڪيو آهي. هي ڇا ڪري رهيو آهي؟ اهو ڪافي ابتدائي آهي. اهو صرف هڪ اعتراض وٺندو آهي ۽ ان مان ڪجهه قدر ڪڍي ٿو جيڪو موازنہ آهي. مثال طور، Integer comparable لاڳو ڪري ٿو، تنهنڪري اسان پيغام جي سڃاڻپ جي قدرن تي compareTo انجام ڏيڻ جي قابل هئاسين. هن سادي comparator فعل به هن طرح لکي سگهجي ٿو:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
اهو آهي، لفظي طور تي، "اسان وٽ هڪ Comparator آهي جيڪو هن طرح سان مقابلو ڪري ٿو: اهو شيون وٺندو آهي، حاصل ڪري ٿو انهن کان Comparable GetId () طريقو استعمال ڪندي، compareTo استعمال ڪندي موازنہ." ۽ نه وڌيڪ خوفناڪ ڊيزائن. ۽ آخر ۾، مان هڪ وڌيڪ خصوصيت نوٽ ڪرڻ چاهيان ٿو. Comparators گڏجي زنجيرن ڪري سگهجي ٿو. مثال طور:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
comparator = comparator.thenComparing(obj -> obj.getMessage().length());

درخواست

مقابلي جو اعلان بلڪل منطقي ثابت ٿيو، ڇا اهو ناهي؟ هاڻي اسان کي ڏسڻ جي ضرورت آهي ته ان کي ڪيئن استعمال ڪجي ۽ ڪهڙن هنڌن تي. → Collections.sort (java.util.Collections) يقينن، اسان هن طرح مجموعن کي ترتيب ڏئي سگهون ٿا. پر سڀ ڪجهه نه، صرف فهرست. ۽ هتي ڪجھ به غير معمولي ناهي، ڇاڪاڻ ته ... اها فهرست آهي جنهن کي انڊيڪس ذريعي هڪ عنصر تائين رسائي جي ضرورت آهي. ۽ هي عنصر نمبر ٻه کي عنصر نمبر ٽي سان تبديل ڪرڻ جي اجازت ڏئي ٿو. تنهن ڪري، هن طريقي سان ترتيب ڏيڻ صرف فهرستن لاء ممڪن آهي:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
Collections.sort(messages, comparator);
Arrays.sort (java.util.Arrays) Arrays پڻ ترتيب ڏيڻ لاءِ آسان آهن. ٻيهر، انڊيڪس ذريعي عناصر تائين رسائي جي ساڳئي سبب لاء. → Descendants of java.util.SortedSet ۽ java.util.SortedMap جيئن اسان کي ياد آهي، سيٽ ۽ نقشو رڪارڊ رکڻ جي ترتيب جي ضمانت نه ٿا ڏين. پر اسان وٽ خاص عمل آهن جيڪي ضمانت جي آرڊر ڏين ٿيون. ۽ جيڪڏهن گڏ ڪرڻ وارا عنصر java.lang.Comparable تي عمل نه ٿا ڪن، ته پوءِ اسان Comparator کي اهڙن مجموعن جي تعمير ڪندڙ ڏانهن منتقل ڪري سگهون ٿا:
Set<Message> msgSet = new TreeSet(comparator);
اسٽريم API اسٽريم ايپي ۾، جيڪو جاوا 8 ۾ ظاهر ٿيو، هڪ مقابلو ڪندڙ توهان کي وهڪرو عناصر تي ڪم کي آسان ڪرڻ جي اجازت ڏئي ٿو. مثال طور، اسان کي 0 کان 999 تائين بي ترتيب نمبرن جي ھڪڙي ترتيب جي ضرورت آھي:
Supplier<Integer> randomizer = () -> new Random().nextInt(1000);
Stream.generate(randomizer)
    .limit(10)
    .sorted(Comparator.naturalOrder())
    .forEach(e -> System.out.println(e));
اسان روڪي سگهون ٿا، پر اتي وڌيڪ دلچسپ مسئلا آهن. مثال طور، توهان کي هڪ نقشو تيار ڪرڻ جي ضرورت آهي، جتي اهم پيغام جي سڃاڻپ آهي. ساڳئي وقت، اسان انهن ڪنجين کي ترتيب ڏيڻ چاهيون ٿا ته جيئن ڪنجيون ترتيب ۾ هجن، ننڍي کان وڏي تائين. اچو ته هن ڪوڊ سان شروع ڪريون:
Map<Integer, Message> collected = Arrays.stream(messages)
                .sorted(Comparator.comparing(msg -> msg.getId()))
                .collect(Collectors.toMap(msg -> msg.getId(), msg -> msg));
جيڪو اسان هتي واپس حاصل ڪنداسين اصل ۾ هڪ HashMap آهي. ۽ جيئن اسان ڄاڻون ٿا، اهو ڪنهن به حڪم جي ضمانت نٿو ڏئي. تنهن ڪري، اسان جا رڪارڊ ID جي ترتيب سان ترتيب ڏنل آهن. سٺو ناهي. اسان کي اسان جي ڪليڪٽر کي ٿورو تبديل ڪرڻو پوندو:
Map<Integer, Message> collected = Arrays.stream(messages)
                .sorted(Comparator.comparing(msg -> msg.getId()))
                .collect(Collectors.toMap(msg -> msg.getId(), msg -> msg, (oldValue, newValue) -> oldValue, TreeMap::new));
ڪوڊ ٿورڙو چريو نظر آيو، پر مسئلو هاڻي صحيح طور تي حل ڪيو ويو آهي TreeMap جي واضح نفاذ جي مهرباني. توهان هتي مختلف گروپن بابت وڌيڪ پڙهي سگهو ٿا: توهان پنهنجو پاڻ کي ڪليڪٽر ٺاهي سگهو ٿا. توهان هتي وڌيڪ پڙهي سگهو ٿا: "جاوا 8 ۾ ڪسٽم ڪليڪٽر ٺاهڻ" . ۽ اهو هتي بحث پڙهڻ لاء مفيد آهي: "جاوا 8 لسٽ سان نقشي سان گڏ" .
جاوا ۾ موازنہ ڪندڙ - 3
Comparator ۽ Comparable rakes سٺا آهن. پر اتي انھن سان لاڳاپيل هڪ nuance آهي ته ياد ڪرڻ جي قابل آهي. جڏهن هڪ ڪلاس ترتيب ڏئي ٿو، اهو حساب ڪري ٿو ته اهو توهان جي ڪلاس کي مقابلي ۾ آڻي سگهي ٿو. جيڪڏهن اهو معاملو نه آهي، توهان کي عمل جي وقت تي هڪ غلطي ملي ويندي. اچو ته هڪ مثال ڏسو:
SortedSet<Message> msg = new TreeSet<>();
msg.add(new Message(2, "Developer".getBytes()));
اهو لڳي ٿو ته هتي ڪجھ به غلط ناهي. پر حقيقت ۾، اسان جي مثال ۾، اهو غلطي سان حادثو ٿيندو: java.lang.ClassCastException: Message cannot be cast to java.lang.Comparable ۽ سڀ ڪجهه ڇاڪاڻ ته اهو عناصر کي ترتيب ڏيڻ جي ڪوشش ڪئي (اهو هڪ ترتيب ڏنل سيٽ آهي، سڀ کان پوء). ۽ مان نه ڪري سگهيو. توهان کي اهو ياد رکڻ گهرجي جڏهن SortedMap ۽ SortedSet سان ڪم ڪندي. اضافي طور تي ڏسڻ لاءِ تجويز ڪيل: Yuri Tkach: HashSet ۽ TreeSet - مجموعا #1 - Advanced Java
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION