Bagaimana cara menggunakan Comparator untuk menentukan tata urutan kustom?


91

Saya ingin mengembangkan demo penyortiran untuk daftar mobil. Saya menggunakan tabel data untuk menampilkan daftar mobil. Sekarang sebenarnya saya ingin mengurutkan daftar berdasarkan warna mobil. Di sini tidak diurutkan berdasarkan urutan abjad. Saya ingin menggunakan urutan penyortiran khusus seperti mobil Merah didahulukan, lalu Biru, dll.

Untuk itu saya mencoba menggunakan Java Comparatordan Comparabletetapi memungkinkan untuk mengurutkan dalam urutan abjad saja.

Jadi, dapatkah ada orang yang memandu saya cara menerapkan teknik yang akan digunakan sehingga penyortiran menjadi lebih cepat.

class Car implements Comparable<Car>
{
    private String name;
    private String color;

    public Car(String name, String color){
        this.name = name;
        this.color = color;
    }

    //Implement the natural order for this class
    public int compareTo(Car c) {
        return name.compareTo(c.name);
    }

    static class ColorComparator implements Comparator<Car> {
        public int compare(Car c1, Car c2) {
            String a1 = c1.color;
            String a2 = c2.color;
            return a1.compareTo(a2);
        }
    }

    public static void main(String[] args) {
        List<Car> carList = new ArrayList<>();
        List<String> sortOrder = new ArrayList<>();

        carList.add(new Car("Ford","Silver"));
        carList.add(new Car("Tes","Blue"));
        carList.add(new Car("Honda","Magenta"));

        sortOrder.add("Silver");
        sortOrder.add("Magenta");
        sortOrder.add("Blue");

        // Now here I am confuse how to implement my custom sort             
    }
}

Jawaban:


101

Saya sarankan Anda membuat enum untuk warna mobil Anda daripada menggunakan Strings dan urutan alami enum akan menjadi urutan Anda mendeklarasikan konstanta.

public enum PaintColors {
    SILVER, BLUE, MAGENTA, RED
}

dan

 static class ColorComparator implements Comparator<CarSort>
 {
     public int compare(CarSort c1, CarSort c2)
     {
         return c1.getColor().compareTo(c2.getColor());
     }
 }

Anda mengubah String menjadi PaintColor dan kemudian pada daftar utama mobil Anda menjadi:

carList.add(new CarSort("Ford Figo",PaintColor.SILVER));

...

Collections.sort(carList, new ColorComparator());

bagaimana cara menjalankan example.PaintColors ini tidak diakses di ColorComparator. Anda dapat mengilustrasikan bagaimana metode utama akan terlihat.
Deepak

apa hasilnya? apakah selalu SILVER dulu?
Deepak

@ Deepak: ya, urutan alami enumnilai adalah urutan di mana nilai-nilainya didefinisikan.
Joachim Sauer

1
@SeanPatrickFloyd Saya tidak berpikir bahwa mengandalkan pengurutan alami enum adalah praktik terbaik.
mike

1
@mike Saya tidak setuju, tetapi ada argumen yang valid untuk kedua sudut pandang
Sean Patrick Floyd

57

Bagaimana dengan ini:

List<String> definedOrder = // define your custom order
    Arrays.asList("Red", "Green", "Magenta", "Silver");

Comparator<Car> comparator = new Comparator<Car>(){

    @Override
    public int compare(final Car o1, final Car o2){
        // let your comparator look up your car's color in the custom order
        return Integer.valueOf(
            definedOrder.indexOf(o1.getColor()))
            .compareTo(
                Integer.valueOf(
                    definedOrder.indexOf(o2.getColor())));
    }
};

Pada prinsipnya, saya setuju bahwa menggunakan an enumadalah pendekatan yang lebih baik, tetapi versi ini lebih fleksibel karena memungkinkan Anda menentukan urutan yang berbeda.

Memperbarui

Jambu biji memiliki fungsi ini yang dimasukkan ke dalam Orderingkelasnya:

List<String> colorOrder = ImmutableList.of("red","green","blue","yellow");
final Ordering<String> colorOrdering = Ordering.explicit(colorOrder);
Comparator<Car> comp = new Comparator<Car>() {
    @Override
    public int compare(Car o1, Car o2) {
        return colorOrdering.compare(o1.getColor(),o2.getColor());
    }
}; 

Versi ini sedikit kurang bertele-tele.


Perbarui lagi

Java 8 membuat Comparator semakin tidak bertele-tele:

Comparator<Car> carComparator = Comparator.comparing(
        c -> definedOrder.indexOf(c.getColor()));

Bisakah Anda melihat pertanyaan ini juga. Terimakasih. stackoverflow.com/questions/61934313/…
pengguna2048204

Comparator<Car> carComparator = Comparator.comparing( c -> definedOrder.indexOf(c.getColor())); melempar kesalahan kompilasi
Santossh Kumhar

@SantosshKumhar berikut ini contoh yang berfungsi: ideone.com/frUbym
Sean Patrick Floyd

25

Pembanding sejalan ...

List<Object> objList = findObj(name);
Collections.sort(objList, new Comparator<Object>() {
    @Override
    public int compare(Object a1, Object a2) {
        return a1.getType().compareToIgnoreCase(a2.getType());
    }
});

11

Saya rasa ini bisa dilakukan sebagai berikut:

class ColorComparator implements Comparator<CarSort>
{
    private List<String> sortOrder;
    public ColorComparator (List<String> sortOrder){
        this.sortOrder = sortOrder;
    }

    public int compare(CarSort c1, CarSort c2)
    {
        String a1 = c1.getColor();
        String a2 = c2.getColor();
        return sortOrder.indexOf(a1) - sortOrder.indexOf(a2);
     }
 }

Untuk menyortir gunakan ini:

Collections.sort(carList, new ColorComparator(sortOrder));

7

Saya harus melakukan sesuatu yang mirip dengan jawaban Sean dan ilalex.
Tetapi saya memiliki terlalu banyak opsi untuk secara eksplisit menentukan urutan sortir dan hanya perlu mengapungkan entri tertentu ke depan daftar ... dalam urutan yang ditentukan (non-natural).
Semoga bermanfaat bagi orang lain.

public class CarComparator implements Comparator<Car> {

    //sort these items in this order to the front of the list 
    private static List<String> ORDER = Arrays.asList("dd", "aa", "cc", "bb");

    public int compare(final Car o1, final Car o2) {
        int result = 0;
        int o1Index = ORDER.indexOf(o1.getName());
        int o2Index = ORDER.indexOf(o2.getName());
        //if neither are found in the order list, then do natural sort
        //if only one is found in the order list, float it above the other
        //if both are found in the order list, then do the index compare
        if (o1Index < 0 && o2Index < 0) result = o1.getName().compareTo(o2.getName());
        else if (o1Index < 0) result = 1;
        else if (o2Index < 0) result = -1;
        else result = o1Index - o2Index;
        return result;
    }

//Testing output: dd,aa,aa,cc,bb,bb,bb,a,aaa,ac,ac,ba,bd,ca,cb,cb,cd,da,db,dc,zz
}

4

Saya akan melakukan sesuatu seperti ini:

List<String> order = List.of("Red", "Green", "Magenta", "Silver");

Comparator.comparing(Car::getColor(), Comparator.comparingInt(c -> order.indexOf(c)))

Semua kredit diberikan kepada @Sean Patrick Floyd :)


3

Di Java 8 Anda dapat melakukan sesuatu seperti ini:

Pertama Anda membutuhkan Enum:

public enum Color {
    BLUE, YELLOW, RED
}

Kelas mobil:

public class Car {

    Color color;

    ....

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }
}

Dan kemudian, menggunakan daftar mobil Anda, Anda cukup melakukan:

Collections.sort(carList, Comparator:comparing(CarSort::getColor));

Ini bukan jenis kustom.
zygimantus

Selain itu, ini bukan cara yang "fungsional" untuk melakukannya ... ini memiliki pengaruh samping !!
TriCore

2

Tentukan satu Jenis Enum sebagai

public enum Colors {
     BLUE, SILVER, MAGENTA, RED
}

Ubah tipe data colordari Stringmenjadi Colors Ubah tipe pengembalian dan tipe argumen metode pengambil dan penyetel warna menjadiColors

Tentukan jenis pembanding sebagai berikut

static class ColorComparator implements Comparator<CarSort>
{
    public int compare(CarSort c1, CarSort c2)
    {
        return c1.getColor().compareTo(c2.getColor());
    }
}

setelah menambahkan elemen ke List, panggil metode sortir Collection dengan melewatkan objek list dan komparator sebagai argumen

yaitu, Collections.sort(carList, new ColorComparator()); kemudian cetak menggunakan ListIterator.

implementasi kelas lengkap adalah sebagai berikut:

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;    
import java.util.ListIterator;

public class CarSort implements Comparable<CarSort>{

    String name;
    Colors color;

    public CarSort(String name, Colors color){
        this.name = name;
        this.color = color;
    } 

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Colors getColor() {
        return color;
    }
    public void setColor(Colors color) {
        this.color = color;
    }

    //Implement the natural order for this class
    public int compareTo(CarSort c)
    {
        return getName().compareTo(c.getName());
    }

    static class ColorComparator implements Comparator<CarSort>
    {
        public int compare(CarSort c1, CarSort c2)
        {
            return c1.getColor().compareTo(c2.getColor());
        }
    }

    public enum Colors {
         BLUE, SILVER, MAGENTA, RED
    }

     public static void main(String[] args)
     {
         List<CarSort> carList = new ArrayList<CarSort>();
         List<String> sortOrder = new ArrayList<String>();

         carList.add(new CarSort("Ford Figo",Colors.SILVER));
         carList.add(new CarSort("Santro",Colors.BLUE));
         carList.add(new CarSort("Honda Jazz",Colors.MAGENTA));
         carList.add(new CarSort("Indigo V2",Colors.RED));
         Collections.sort(carList, new ColorComparator());

         ListIterator<CarSort> itr=carList.listIterator();
         while (itr.hasNext()) {
            CarSort carSort = (CarSort) itr.next();
            System.out.println("Car colors: "+carSort.getColor());
        }
     }
}

0

Hanya menggunakan loop sederhana:

public static void compareSortOrder (List<String> sortOrder, List<String> listToCompare){
        int currentSortingLevel = 0;
        for (int i=0; i<listToCompare.size(); i++){
            System.out.println("Item from list: " + listToCompare.get(i));
            System.out.println("Sorting level: " + sortOrder.get(currentSortingLevel));
            if (listToCompare.get(i).equals(sortOrder.get(currentSortingLevel))){

            } else {
                try{
                    while (!listToCompare.get(i).equals(sortOrder.get(currentSortingLevel)))
                        currentSortingLevel++;
                    System.out.println("Changing sorting level to next value: " + sortOrder.get(currentSortingLevel));
                } catch (ArrayIndexOutOfBoundsException e){

                }

            }
        }
    }

Dan urutkan urutan dalam Daftar

public static List<String> ALARMS_LIST = Arrays.asList(
            "CRITICAL",
            "MAJOR",
            "MINOR",
            "WARNING",
            "GOOD",
            "N/A");
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.