Cara mengurutkan Daftar <Objek> menurut abjad menggunakan kolom Nama objek

103

Saya memiliki Daftar Objek seperti. List<Object> pSaya ingin mengurutkan daftar ini menurut abjad menggunakan bidang nama Objek. Objek berisi 10 bidang dan bidang nama adalah salah satunya.

if (list.size() > 0) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(final Object object1, final Object object2) {
        return String.compare(object1.getName(), object2.getName());
        }
    } );
}

Tapi tidak ada yang seperti String.compare ..?

Saurabh Kumar
sumber
3
Bagaimana Anda akan mendapatkan nama itu? - ObjectTidak punya nama. Apakah maksud Anda menggunakan .toString()?
Matt Fenwick
object1dan object2harus bertipe Campaign, dan fungsi bandingkan adalah object1.getName().compareTo(object2.getName()).
Bart van Heukelom
Anda mencampur List<Object>dan Comparator<Campaign>. Kamu tidak boleh melakukan itu. Entah Anda memiliki List<Object>dan Comparator<Object>atau List<Campaign>danComparator<Campaign>
viktor

Jawaban:

231

Dari kode Anda, sepertinya Anda Comparatorsudah diparameterisasi dengan Campaign. Ini hanya akan bekerja dengan List<Campaign>. Juga, metode yang Anda cari adalah compareTo.

if (list.size() > 0) {
  Collections.sort(list, new Comparator<Campaign>() {
      @Override
      public int compare(final Campaign object1, final Campaign object2) {
          return object1.getName().compareTo(object2.getName());
      }
  });
}

Atau jika Anda menggunakan Java 1.8

list
  .stream()
  .sorted((object1, object2) -> object1.getName().compareTo(object2.getName()));

Satu komentar terakhir - tidak ada gunanya memeriksa ukuran daftar. Sortir akan berfungsi pada daftar kosong.

Robert B
sumber
2
Saya pikir ini adalah jawaban terbaik yang menyaring segalanya menjadi apa yang dicari OP. Dan dari komentarnya, saya pikir dia ingin case-insensitive, jadi ganti saja CompareTo ke CompareToIgnoreCase
Greg Case
Perbaikan kecil di solusi pertama: kita bisa lakukan jika (list.size ()> 1) - adapun 1 item tidak perlu diurutkan ..
Rami Yampolsky
12
Anda dapat menggunakanComparator.comparing(Campaign::getName)
Jose Da Silva
4
list.sort((object1, object2) -> object1. getName().compareTo(object2. getName()));bekerja untuk saya
Lucas
1
Coba gunakan sortedList = list.stream().sort((object1, object2) -> object1. getName().compareTo(object2. getName()))..collect(Collectors.toList());untuk mendapatkan daftar baru yang diurutkan
Lukas
16

Cara paling benar untuk mengurutkan string menurut abjad adalah dengan menggunakan Collator, karena internasionalisasi. Beberapa bahasa memiliki urutan berbeda karena sedikit karakter tambahan, dll.

   Collator collator = Collator.getInstance(Locale.US);
   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return collator.compare(c1.getName(), c2.getName());
        }
       });
   }

Jika Anda tidak peduli tentang penggunaan internasionalisasi string.compare(otherString).

   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return c1.getName().compare(c2.getName());
        }
       });
   }
Viktor
sumber
11

Lihat Collections.sort()dan Comparatorantarmukanya.

Perbandingan string dapat dilakukan dengan object1.getName().compareTo(object2.getName())atau object2.getName().compareTo(object1.getName())(tergantung pada arah pengurutan yang Anda inginkan).

Jika Anda ingin jenis menjadi case agnostic, lakukan object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase()).

tobiasbayer
sumber
dan bagaimana Anda menyarankan mengekstraksi bidang yang dipanggil namadari Objectjenis? jawaban ini tidak lengkap.
amit
Ekstraksi nama bergantung pada jenis objek. Saya kira itu hanya tipe placeholder. Jika Anda tidak bisa memberikan tipe yang lebih konkret, Anda bisa mengakhirinya dengan menggunakan refleksi.
tobiasbayer
9

Menggunakan Java 8 Comparator.comparing :

list.sort(Comparator.comparing(Campaign::getName));
Oleksandr Pyrohov
sumber
7
public class ObjectComparator implements Comparator<Object> {

    public int compare(Object obj1, Object obj2) {
        return obj1.getName().compareTo(obj2.getName());
    }

}

Silakan ganti Objek dengan kelas Anda yang berisi kolom nama

Pemakaian:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);
Jan Vorcak
sumber
Saya melakukan ini tetapi "tes" datang sebelum "Pencarian".: (((
Saurabh Kumar
jika Anda ingin membuat penyortiran terbalik, ganti saja obj1.getName().compareTo(obj2.getName()dengan obj2.getName().compareTo(obj1.getName()di kelas pembanding
Jan Vorcak
2

sesuatu seperti

  List<FancyObject> theList =  ;
  Collections.sort (theList,
                    new Comparator<FancyObject> ()
                    { int compare (final FancyObject a, final FancyObject d)
                          { return (a.getName().compareTo(d.getName())); }});
BRPocock
sumber
2

Berikut adalah versi jawaban Robert B yang berfungsi untuk List<T>dan menyortir berdasarkan properti String tertentu dari objek menggunakan Refleksi dan tidak ada pustaka pihak ketiga

/**
 * Sorts a List by the specified String property name of the object.
 * 
 * @param list
 * @param propertyName
 */
public static <T> void sortList(List<T> list, final String propertyName) {

    if (list.size() > 0) {
        Collections.sort(list, new Comparator<T>() {
            @Override
            public int compare(final T object1, final T object2) {
                String property1 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object1);
                String property2 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object2);
                return property1.compareToIgnoreCase (property2);
            }
        });
    }
}


public static Object getSpecifiedFieldValue (String property, Object obj) {

    Object result = null;

    try {
        Class<?> objectClass = obj.getClass();
        Field objectField = getDeclaredField(property, objectClass);
        if (objectField!=null) {
            objectField.setAccessible(true);
            result = objectField.get(obj);
        }
    } catch (Exception e) {         
    }
    return result;
}

public static Field getDeclaredField(String fieldName, Class<?> type) {

    Field result = null;
    try {
        result = type.getDeclaredField(fieldName);
    } catch (Exception e) {
    }       

    if (result == null) {
        Class<?> superclass = type.getSuperclass();     
        if (superclass != null && !superclass.getName().equals("java.lang.Object")) {       
            return getDeclaredField(fieldName, type.getSuperclass());
        }
    }
    return result;
}
che javara
sumber
2

Anda dapat menggunakan sortThisBy()dari Koleksi Eclipse :

MutableList<Campaign> list = Lists.mutable.empty();
list.sortThisBy(Campaign::getName);

Jika Anda tidak dapat mengubah jenis daftar dari List:

List<Campaign> list = new ArrayList<>();
ListAdapter.adapt(list).sortThisBy(Campaign::getName);

Catatan: Saya adalah kontributor Koleksi Eclipse.

Nikhil Nanivadekar
sumber
2

Coba ini:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));
Alper Karaağaçlı
sumber
FYI jika Anda melakukan ini di Android, ini memerlukan setidaknya API level 24
MSpeed
1

Jika benda Anda memiliki beberapa nenek moyang [biarlah T] Anda harus menggunakan List<T>bukan List<Object>, dan menerapkan komparator untuk T ini, menggunakan kolom nama.

Jika Anda tidak memiliki leluhur yang sama, Anda dapat mengimplementasikan Comperator, dan menggunakan refleksi untuk mengekstrak nama, Perhatikan bahwa itu tidak aman, tidak disarankan, dan mengalami kinerja buruk untuk menggunakan refleksi, tetapi memungkinkan Anda untuk mengakses nama bidang tanpa mengetahui apa pun tentang jenis objek yang sebenarnya [selain fakta bahwa ia memiliki bidang dengan nama yang relevan]

Dalam kedua kasus, Anda harus menggunakan Collections.sort () untuk mengurutkan.

amit
sumber
1

Saya menemukan cara lain untuk melakukan tipe.

if(listAxu.size() > 0){
    Collections.sort(listAxu, Comparator.comparing(IdentityNamed::getDescricao));
}
Rafael Mendes
sumber
0

Ini mengasumsikan daftar YourClassbukan Object, seperti yang dijelaskan oleh amit .

Anda dapat menggunakan bit ini dari pustaka Google Guava:

Collections.sort(list, Ordering.natural()
  .onResultOf(new Function<String,YourClass>() {
  public String call(YourClass o) {
     return o.getName();
  }))
  .nullsLast();

Jawaban lain yang menyebutkan Comparatortidak salah, karena Orderingdiimplementasikan Comparator. Solusi ini, menurut saya, sedikit lebih mudah, meskipun mungkin lebih sulit jika Anda seorang pemula dan tidak terbiasa menggunakan perpustakaan dan / atau "pemrograman fungsional".

Disalin tanpa malu-malu dari jawaban ini pada pertanyaan saya sendiri.

Bart van Heukelom
sumber
Ini adalah cara saya melakukannya, tetapi mungkin terlalu berlebihan untuk OP.
Greg Case
0

Menggunakan pilihan Sort

for(int i = list.size() - 1; i > 0; i--){

  int max = i

  for(int j = 0; j < i; j++){
      if(list.get(j).getName().compareTo(list.get(j).getName()) > 0){
            max= j;
      }
  }

  //make the swap
  Object temp = list.get(i);
  list.get(i) = list.get(max);
  list.get(max) = temp;

}
Shizumaru 18
sumber
(1) Mengapa dia menemukan kembali roda? apa yang salah dengan Collections.sort()? (2) daftar bertipe List<Object>, dan karena itu list.get(j).getName()tidak dapat dikompilasi. (3) solusi ini adalah O (n ^ 2), sedangkan menggunakan Collections.sort()solusi O (nlogn) yang lebih baik.
amit
0

Jika Anda menggunakan a List<Object>untuk menampung objek dari subtipe yang memiliki bidang nama (sebut saja subtipe NamedObject), Anda harus menurunkan elemen daftar untuk mengakses nama. Anda memiliki 3 opsi, yang terbaik adalah yang pertama:

  1. Jangan gunakan a List<Object>di tempat pertama jika Anda bisa membantunya - simpan objek bernama Anda di aList<NamedObject>
  2. Salin List<Object>elemen Anda ke a List<NamedObject>, dalam proses downcasting, lakukan penyortiran, lalu salin kembali
  3. Lakukan downcasting di Comparator

Opsi 3 akan terlihat seperti ini:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}
Mike E
sumber
0
if(listAxu.size() > 0){
     Collections.sort(listAxu, new Comparator<Situacao>(){
        @Override
        public int compare(Situacao lhs, Situacao rhs) {            
            return lhs.getDescricao().compareTo(rhs.getDescricao());
        }
    });
 }
George Freire
sumber
1
Mau menjelaskan lebih lanjut daripada hanya membuang kode dalam pertanyaan 3 tahun?
Holloway
0

Jawaban @ Victor berhasil untuk saya dan memposting ulang di sini di Kotlin seandainya berguna bagi orang lain yang menggunakan Android.

if (list!!.isNotEmpty()) {
   Collections.sort(
     list,
     Comparator { c1, c2 -> //You should ensure that list doesn't contain null values!
     c1.name!!.compareTo(c2.name!!)
   })
}
Francislainy Campos
sumber