আমি কীভাবে বিভিন্ন সময় অনুসারে বিভিন্ন পরামিতিগুলির দ্বারা তালিকাটিকে সাজান


95

আমার Personএকাধিক বৈশিষ্ট্যযুক্ত একটি ক্লাস রয়েছে , উদাহরণস্বরূপ:

public class Person {
    private int id;
    private String name, address;
    // Many more properties.
}

প্রচুর- Personপ্রকল্পগুলি একটিতে সঞ্চিত থাকে ArrayList<Person>। আমি এই তালিকাটিকে একাধিক বাছাই পরামিতি অনুসারে এবং বিভিন্ন সময়ে সময়ে আলাদা করতে চাই। উদাহরণস্বরূপ আমি nameএকবারে আরোহী এবং তারপরে addressনামার মাধ্যমে বাছাই করতে চাই এবং অন্য সময় কেবল নীচে idনামার মাধ্যমে।

এবং আমি আমার নিজস্ব সাজানোর পদ্ধতিগুলি তৈরি করতে চাই না (যেমন, আমি ব্যবহার করতে চাই Collections.sort(personList, someComparator)this এটি প্রাপ্ত সবচেয়ে সার্থক সমাধান কী?

উত্তর:


192

আমি মনে করি আপনার এনাম অ্যাপ্রোচটি মূলত সাবলীল, তবে স্যুইচ স্টেটমেন্টগুলিতে সত্যিকার অর্থে আরও একটি অবজেক্ট ওরিয়েন্টেড অ্যাপ্রোচ দরকার। বিবেচনা:

enum PersonComparator implements Comparator<Person> {
    ID_SORT {
        public int compare(Person o1, Person o2) {
            return Integer.valueOf(o1.getId()).compareTo(o2.getId());
        }},
    NAME_SORT {
        public int compare(Person o1, Person o2) {
            return o1.getFullName().compareTo(o2.getFullName());
        }};

    public static Comparator<Person> decending(final Comparator<Person> other) {
        return new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                return -1 * other.compare(o1, o2);
            }
        };
    }

    public static Comparator<Person> getComparator(final PersonComparator... multipleOptions) {
        return new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                for (PersonComparator option : multipleOptions) {
                    int result = option.compare(o1, o2);
                    if (result != 0) {
                        return result;
                    }
                }
                return 0;
            }
        };
    }
}

ব্যবহারের একটি উদাহরণ (একটি স্ট্যাটিক আমদানি সহ)।

public static void main(String[] args) {
    List<Person> list = null;
    Collections.sort(list, decending(getComparator(NAME_SORT, ID_SORT)));
}

12
এনামগুলির +1 স্মার্ট ব্যবহার। আপনি enums, "অবতরণ" এবং "কম্পোজিট" এর সাথে আপনার যে মার্জিত সমন্বয়টি করতে চান তা পছন্দ করি। আমি অনুমান করি যে নাল মানগুলি চিকিত্সাটি অনুপস্থিত, তবে "অবতরণ" এর মতোই যুক্ত করা সহজ।
KLE

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

4
@TheLittleNaruto, তুলনা পদ্ধতি o2 বেশি হলে একটি ধনাত্মক সংখ্যা, o1 বেশি হলে একটি ধনাত্মক এবং তারা সমান হলে শূন্য প্রদান করে। -1 দিয়ে গুণ করলে ফলাফলটি বিপরীত হয় যা প্রতারণামূলক ধারণা (সাধারণ আরোহী ক্রমের বিপরীত) হয়, যখন এটি সমান হলে শূন্য হিসাবে রেখে যায়।
যিশাই

4
নোট করুন যে জাভা 8 এর পরে আপনি উতরাইয়ের জন্য comparator.reversed()ব্যবহার করতে পারেন এবং আপনি comparator1.thenComparing(comparator2)চেইন তুলকগুলির জন্য ব্যবহার করতে পারেন ।
গুইসিম

4
@ জোহানবাউম, প্রথম তুলনাকারী যদি শূন্যহীন ফলাফল প্রদান করে তবে ফলাফলটি ফিরে আসে এবং বাকী শৃঙ্খলা কার্যকর হয় না।
যিশাই

26

আপনি যে বৈশিষ্ট্যগুলি বাছাই করতে পারেন তার প্রতিটিগুলির জন্য তুলনামূলক তৈরি করতে পারেন এবং তারপরে "তুলনামূলক শৃঙ্খলা" :-) চেষ্টা করে দেখতে পারেন:

public class ChainedComparator<T> implements Comparator<T> {
    private List<Comparator<T>> simpleComparators; 
    public ChainedComparator(Comparator<T>... simpleComparators) {
        this.simpleComparators = Arrays.asList(simpleComparators);
    }
    public int compare(T o1, T o2) {
        for (Comparator<T> comparator : simpleComparators) {
            int result = comparator.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

এটি ব্যবহার করার সময় আপনি সম্ভবত একটি সতর্কতা পেতে যাচ্ছেন (যদিও জেডিকে in এ আপনার এটি দমন করতে সক্ষম হওয়া উচিত)।
টম হাটিন -

আমি এটিও পছন্দ করি। আপনি কীভাবে প্রদত্ত উদাহরণ সহ এটি ব্যবহার করবেন তার একটি নমুনা সরবরাহ করতে পারেন?
রানারস

@ রুনারোস: কেএলইয়ের উত্তর থেকে তুলনাকারী ব্যবহার করে: সংগ্রহসমূহ sসার্ট (/ * সংগ্রহ <পার্সন> * / জনগণ, নতুন চেইনডকম্পেরেটর (NAME_ASC_ADPress_DESC, ID_DESC));
জানুস ট্রয়লসেন

16

একটি উপায় হ'ল একটি তৈরি করা Comparatorযা আর্গুমেন্ট হিসাবে বিবেচনা করে বাছাই করার জন্য বৈশিষ্ট্যগুলির তালিকান, যেমন এই উদাহরণটি দেখায়।

public class Person {
    private int id;
    private String name, address;

    public static Comparator<Person> getComparator(SortParameter... sortParameters) {
        return new PersonComparator(sortParameters);
    }

    public enum SortParameter {
        ID_ASCENDING, ID_DESCENDING, NAME_ASCENDING,
        NAME_DESCENDING, ADDRESS_ASCENDING, ADDRESS_DESCENDING
    }

    private static class PersonComparator implements Comparator<Person> {
        private SortParameter[] parameters;

        private PersonComparator(SortParameter[] parameters) {
            this.parameters = parameters;
        }

        public int compare(Person o1, Person o2) {
            int comparison;
            for (SortParameter parameter : parameters) {
                switch (parameter) {
                    case ID_ASCENDING:
                        comparison = o1.id - o2.id;
                        if (comparison != 0) return comparison;
                        break;
                    case ID_DESCENDING:
                        comparison = o2.id - o1.id;
                        if (comparison != 0) return comparison;
                        break;
                    case NAME_ASCENDING:
                        comparison = o1.name.compareTo(o2.name);
                        if (comparison != 0) return comparison;
                        break;
                    case NAME_DESCENDING:
                        comparison = o2.name.compareTo(o1.name);
                        if (comparison != 0) return comparison;
                        break;
                    case ADDRESS_ASCENDING:
                        comparison = o1.address.compareTo(o2.address);
                        if (comparison != 0) return comparison;
                        break;
                    case ADDRESS_DESCENDING:
                        comparison = o2.address.compareTo(o1.address);
                        if (comparison != 0) return comparison;
                        break;
                }
            }
            return 0;
        }
    }
}

এটি কোডের ক্ষেত্রে উদাহরণস্বরূপ ব্যবহার করা যেতে পারে:

cp = Person.getComparator(Person.SortParameter.ADDRESS_ASCENDING,
                          Person.SortParameter.NAME_DESCENDING);
Collections.sort(personList, cp);

হ্যাঁ. আপনি যদি নিজের কোডটি খুব জেনারিক হতে চান তবে আপনার এনাম পড়ার জন্য কেবলমাত্র সম্পত্তিটি নির্দিষ্ট করতে পারে (আপনি এনাম নাম ব্যবহার করে সম্পত্তি পেতে প্রতিচ্ছবি ব্যবহার করতে পারেন), এবং বাকিটি দ্বিতীয় এনাম সহ নির্দিষ্ট করতে পারেন: এএসসি এবং ডিইএসসি, এবং সম্ভবত তৃতীয় (NULL_FIRST বা NULL_LAST)।
কেএলই

8

একটি পদ্ধতির Comparatorএস রচনা করা হবে । এটি একটি গ্রন্থাগার পদ্ধতি হতে পারে (আমি নিশ্চিত এটি এটি কোথাও কোথাও বিদ্যমান)।

public static <T> Comparator<T> compose(
    final Comparator<? super T> primary,
    final Comparator<? super T> secondary
) {
    return new Comparator<T>() {
        public int compare(T a, T b) {
            int result = primary.compare(a, b);
            return result==0 ? secondary.compare(a, b) : result;
        }
        [...]
    };
}

ব্যবহার:

Collections.sort(people, compose(nameComparator, addressComparator));

বিকল্পভাবে, নোট করুন এটি Collections.sortএকটি স্থিতিশীল সাজান। যদি পারফরম্যান্স একেবারে গুরুত্বপূর্ণ না হয় তবে আপনি প্রাথমিকের আগে গৌণ ক্রমটি সাজান।

Collections.sort(people, addressComparator);
Collections.sort(people, nameComparator);

চতুর পন্থা, তবে, এটি আরও জেনেরিক করা যেতে পারে, যেমন এটিতে শূন্য সহ সম্ভবত তুলনামূলক একটি সংখ্যক অন্তর্ভুক্ত রয়েছে?
রানারস

compose(nameComparator, compose(addressComparator, idComparator))জাভাতে এক্সটেনশন পদ্ধতি থাকলে এটি আরও ভালভাবে পড়তে পারে।
টম হাটিন -

4

তুলনাকারীরা আপনাকে এটি খুব সহজে এবং প্রাকৃতিকভাবে করতে দেয়। আপনি তুলনামূলক একক দৃষ্টান্ত তৈরি করতে পারেন, হয় নিজেই আপনার ব্যক্তি শ্রেণিতে, বা আপনার প্রয়োজনের সাথে সম্পর্কিত কোনও পরিষেবা শ্রেণিতে।
উদাহরণস্বরূপ, বেনামে অভ্যন্তরীণ ক্লাস ব্যবহার করে:

    public static final Comparator<Person> NAME_ASC_ADRESS_DESC
     = new Comparator<Person>() {
      public int compare(Person p1, Person p2) {
         int nameOrder = p1.getName().compareTo(p2.getName);
         if(nameOrder != 0) {
           return nameOrder;
         }
         return -1 * p1.getAdress().comparedTo(p2.getAdress());
         // I use explicit -1 to be clear that the order is reversed
      }
    };

    public static final Comparator<Person> ID_DESC
     = new Comparator<Person>() {
      public int compare(Person p1, Person p2) {
         return -1 * p1.getId().comparedTo(p2.getId());
         // I use explicit -1 to be clear that the order is reversed
      }
    };
    // and other comparator instances as needed... 

আপনার যদি অনেকগুলি থাকে তবে আপনি নিজের তুলনামূলক কোডকে আপনার পছন্দ মতো কোনও কাঠামো তৈরি করতে পারেন। উদাহরণস্বরূপ, আপনি করতে পারেন:

  • অন্য তুলক থেকে উত্তরাধিকারী,
  • একটি কম্পোজিটকম্পারেটর রয়েছে যা কিছু বিদ্যমান তুলনামূলককে একত্রিত করে
  • নালকম্পারেটর রয়েছে যা নাল কেসগুলি পরিচালনা করে, তারপরে অন্য তুলকের সাথে প্রতিনিধি প্রেরণ করে
  • ইত্যাদি ...

2

আমি মনে করি আপনার উত্তরের মতো পার্সোনার ক্লাসে সংযোজন করা ভাল ধারণা নয়, কারণ এটি তুলনামূলক (সাধারণত ব্যবসায়িক চালিত) এবং মডেলকে একে অপরের সাথে বন্ধুত্বপূর্ণ করে তোলে। প্রতিবার আপনি যখন বাছাইয়ের কিছু পরিবর্তন / যুক্ত করতে চান তখন আপনাকে ব্যক্তি শ্রেণীর স্পর্শ করতে হবে যা সাধারণত আপনি কিছু করতে চান না।

কোনও পরিষেবা বা অনুরূপ কিছু ব্যবহার করা, যা তুলনামূলক উদাহরণগুলি সরবরাহ করে যেমন কেএলই প্রস্তাবিত, আরও নমনীয় এবং এক্সটেনসেবল শোনায়।


আমার পক্ষে এটি দৃ tight় সংশ্লেষের দিকে পরিচালিত করে কারণ কোনওভাবে তুলনাকারী ধারক শ্রেণি কোনও ব্যক্তি শ্রেণির বিশদ ডেটা কাঠামো জানতে (মূলত ব্যক্তি শ্রেণীর ক্ষেত্রগুলির সাথে তুলনামূলকভাবে কোন ক্ষেত্রের তুলনা করতে পারে) জানতে পারে এবং যদি আপনি কখনও ব্যক্তি ক্ষেত্রে কোন কিছু পরিবর্তন করতে চান তবে এটি একইরকম ট্রেস তৈরি করে leads তুলনামূলক শ্রেণিতে পরিবর্তন আমার ধারণা পার্সন তুলককারীদের একজন ব্যক্তি শ্রেণির অংশ হওয়া উচিত। blog.sanaulla.info/2008/06/26/…
স্টান

2

আমার পন্থা ইশাইয়ের উপর ভিত্তি করে তৈরি। মূল ফাঁকটি হ'ল প্রথমে কোনও অ্যাট্রিবিউটের জন্য আরোহণ বাছাই করার কোনও উপায় নেই এবং এর পরে অন্যটির জন্য প্রতারণা। এটি গণনা দিয়ে করা যায় না। তার জন্য আমি ক্লাস ব্যবহার করেছি। কারণ বাছাই করা অর্ডারটি দৃ strongly়ভাবে নির্ভর করে যে ধরণের ব্যক্তির অন্তর্গত শ্রেণি হিসাবে আমি এটি প্রয়োগ করতে পছন্দ করেছিলাম।

অভ্যন্তর শ্রেণি 'সোর্টারর্ডার' সহ শ্রেণি 'ব্যক্তি':

import java.util.Comparator;

public class Person {
    private int id;
    private String firstName; 
    private String secondName;

    public Person(int id, String firstName, String secondName) {
        this.id = id;
        this.firstName = firstName;
        this.secondName = secondName;   
    }

    public abstract static class SortOrder implements Comparator<Person> {
        public static SortOrder PERSON_ID = new SortOrder() {
            public int compare(Person p1, Person p2) {
                return Integer.valueOf(p1.getId()).compareTo(p2.getId());
            }
        };
        public static SortOrder PERSON_FIRST_NAME = new SortOrder() {
            public int compare(Person p1, Person p2) {
                return p1.getFirstName().compareTo(p2.getFirstName());
            }
        };
        public static SortOrder PERSON_SECOND_NAME = new SortOrder() {
            public int compare(Person p1, Person p2) {
                return p1.getSecondName().compareTo(p2.getSecondName());
            }
        };

        public static SortOrder invertOrder(final SortOrder toInvert) {
            return new SortOrder() {
                public int compare(Person p1, Person p2) {
                    return -1 * toInvert.compare(p1, p2);
                }
            };
        }

        public static Comparator<Person> combineSortOrders(final SortOrder... multipleSortOrders) {
            return new Comparator<Person>() {
                public int compare(Person p1, Person p2) {
                    for (SortOrder personComparator: multipleSortOrders) {
                        int result = personComparator.compare(p1, p2);
                        if (result != 0) {
                            return result;
                        }
                    }
                    return 0;
                }
            };
        }
    }

    public int getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getSecondName() {
        return secondName;
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();

        result.append("Person with id: ");
        result.append(id);
        result.append(" and firstName: ");
        result.append(firstName);
        result.append(" and secondName: ");
        result.append(secondName);
        result.append(".");

        return result.toString();
    }
}

শ্রেণি ব্যক্তি এবং এর SortOrder ব্যবহারের জন্য একটি উদাহরণ:

import static multiplesortorder.Person.SortOrder.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import multiplesortorder.Person;

public class Application {

    public static void main(String[] args) {
        List<Person> listPersons = new ArrayList<Person>(Arrays.asList(
                 new Person(0, "...", "..."),
                 new Person(1, "...", "...")
             ));

         Collections.sort(listPersons, combineSortOrders(PERSON_FIRST_NAME, invertOrder(PERSON_ID)));

         for (Person p: listPersons) {
             System.out.println(p.toString());
         }
    }
}

oRUMOo


তুলনাকারীদের এই ধরণের শৃঙ্খলার জটিলতা কী হবে? আমরা যখন প্রতিযোগীতার সাথে শৃঙ্খল করি তখন কি আমরা মূলত বাছাই করি? সুতরাং আমরা প্রতিটি তুলকের জন্য একটি * লগ (এন) অপারেশন করব?
জন বাউম

0

আমি সম্প্রতি একটি সীমিত স্ট্রিং রেকর্ডের মধ্যে একাধিক ক্ষেত্রগুলি বাছাই করতে একটি তুলনামূলক লিখেছি। এটি আপনাকে ডিলিমিটার, রেকর্ড কাঠামো এবং বাছাইয়ের নিয়ম (যার মধ্যে কয়েকটি টাইপ-নির্দিষ্ট নির্দিষ্ট) সংজ্ঞায়িত করতে দেয়। আপনি এটি কোনও ব্যক্তির রেকর্ডকে একটি সীমিত স্ট্রিংয়ে রূপান্তর করে ব্যবহার করতে পারেন।

প্রয়োজনীয় তথ্য প্রোগ্রামের মাধ্যমে বা একটি এক্সএমএল ফাইলের মাধ্যমে তুলনামূলকভাবে নিজেই তৈরি করা হয়।

এক্সএমএল একটি প্যাকেজ এমবেডেড এক্সএসডি ফাইল দ্বারা যাচাই করা হয়েছে। উদাহরণস্বরূপ, নীচে একটি চারটি ক্ষেত্র সহ একটি ট্যাব সীমিত রেকর্ড লেআউট (যার মধ্যে দুটি সারণযোগ্য):

<?xml version="1.0" encoding="ISO-8859-1"?> 
<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <delimiter>&#009;</delimiter>

    <column xsi:type="Decimal">
        <name>Column One</name>
    </column>

    <column xsi:type="Integer">
        <name>Column Two</name>
    </column>

    <column xsi:type="String">
        <name>Column Three</name>
        <sortOrder>2</sortOrder>
        <trim>true</trim>
        <caseSensitive>false</caseSensitive>        
        <stripAccents>true</stripAccents>
    </column>

    <column xsi:type="DateTime">
        <name>Column Four</name>
        <sortOrder>1</sortOrder>
        <ascending>true</ascending>
        <nullLowSortOrder>true</nullLowSortOrder>
        <trim>true</trim>
        <pattern>yyyy-MM-dd</pattern>
    </column>

</row>

আপনি এটি তখন জাভাতে এটি ব্যবহার করতে পারেন:

Comparator<String> comparator = new RowComparator(
              new XMLStructureReader(new File("layout.xml")));

পাঠাগার এখানে পাওয়া যাবে:

http://sourceforge.net/projects/multicolumnrowcomparator/


0

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

class Coordinate
{

    int x,y;

    public Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }

    static Comparator<Coordinate> getCoordinateXComparator() {
        return new Comparator<Coordinate>() {

            @Override
            public int compare(Coordinate Coordinate1, Coordinate Coordinate2) {
                if(Coordinate1.x < Coordinate2.x)
                    return 1;
                else
                    return 0;
            }
            // compare using Coordinate x
        };
    }

    static Comparator<Coordinate> getCoordinateYComparator() {
        return new Comparator<Coordinate>() {

            @Override
            public int compare(Coordinate Coordinate1, Coordinate Coordinate2) {
                if(Coordinate1.y < Coordinate2.y)
                    return 1;
                else
                    return 0;
            }
            // compare using Coordinate y
        };
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.