Jak sortować listę <Object> alfabetycznie przy użyciu pola Nazwa obiektu

103

Mam listę obiektów, takich jak. List<Object> pChcę posortować tę listę alfabetycznie przy użyciu pola Nazwa obiektu. Obiekt zawiera 10 pól, a jednym z nich jest pole nazwy.

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());
        }
    } );
}

Ale nie ma nic takiego jak String.compare ..?

Saurabh Kumar
źródło
3
Jak zdobędziesz to imię? - Objectnie mają nazw. Czy masz na myśli używanie .toString()?
Matt Fenwick
object1i object2muszą być typu Campaign, a funkcja porównania jest object1.getName().compareTo(object2.getName()).
Bart van Heukelom
Miksujesz List<Object>i Comparator<Campaign>. Nie możesz tego zrobić. Albo masz List<Object>i Comparator<Object>lub List<Campaign>iComparator<Campaign>
viktor

Odpowiedzi:

231

Z twojego kodu wygląda na to, że twój Comparatorjest już sparametryzowany za pomocą Campaign. To zadziała tylko z List<Campaign>. Ponadto metoda, której szukasz, to 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());
      }
  });
}

Lub jeśli używasz Java 1.8

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

Ostatnia uwaga - nie ma sensu sprawdzać rozmiaru listy. Sortowanie będzie działać na pustej liście.

Robert B.
źródło
2
Myślę, że jest to najlepsza odpowiedź, która destyluje wszystko do tego, czego szuka PO. A z komentarzy myślę, że chce, aby wielkość liter nie była rozróżniana, więc po prostu przełącz porównanie na porównaćToIgnoreCase
Greg Case,
Niewielka poprawa w pierwszym rozwiązaniu: możemy zrobić, jeśli (list.size ()> 1) - co do 1 pozycji nie ma potrzeby sortowania ..
Rami Yampolsky
12
Możesz użyćComparator.comparing(Campaign::getName)
Jose Da Silva
4
list.sort((object1, object2) -> object1. getName().compareTo(object2. getName()));pracował dla mnie
Lucas
1
Spróbuj użyć, sortedList = list.stream().sort((object1, object2) -> object1. getName().compareTo(object2. getName()))..collect(Collectors.toList());aby uzyskać nową posortowaną listę
Lukas,
16

Najbardziej poprawnym sposobem alfabetycznego sortowania ciągów jest użycie Collatorze względu na internacjonalizację. Niektóre języki mają inną kolejność ze względu na kilka dodatkowych znaków itp.

   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());
        }
       });
   }

Jeśli nie zależy Ci na internacjonalizacji, użyj 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());
        }
       });
   }
Wiktor
źródło
11

Spójrz na Collections.sort()i Comparatorinterfejs.

Porównanie ciągów można wykonać za pomocą object1.getName().compareTo(object2.getName())lub object2.getName().compareTo(object1.getName())(w zależności od pożądanego kierunku sortowania).

Jeśli chcesz, aby sortowanie było niezależne od wielkości liter, zrób to object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase()).

tobiasbayer
źródło
i jak sugerujesz wyodrębnienie tego pola wywołanego namaz Objecttypu? ta odpowiedź nie jest kompletna.
amit
Wyodrębnianie nazw zależy od typu obiektu. Przypuszczam, że to tylko typ zastępczy. Jeśli nie możesz podać bardziej konkretnego typu, możesz skończyć z refleksją.
tobiasbayer
9

Korzystanie z Java 8 Comparator.comparing :

list.sort(Comparator.comparing(Campaign::getName));
Oleksandr Pyrohov
źródło
7
public class ObjectComparator implements Comparator<Object> {

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

}

Zastąp Object swoją klasą, która zawiera pole nazwy

Stosowanie:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);
Jan Vorcak
źródło
Zrobiłem to, ale „testy” pojawiają się przed „Wyszukiwanie”.: (((
Saurabh Kumar
jeśli chcesz o make odwrotnej sortowania, wystarczy wymienić obj1.getName().compareTo(obj2.getName()ze obj2.getName().compareTo(obj1.getName()w klasie porównawczy
Jan Vorcak
2

coś jak

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

Oto wersja odpowiedzi Roberta B, która działa List<T>i sortuje według określonej właściwości String obiektu przy użyciu odbicia i bez bibliotek innych firm

/**
 * 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
źródło
2

Możesz użyć sortThisBy()z kolekcji Eclipse :

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

Jeśli nie możesz zmienić typu listy z List:

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

Uwaga: współtworzę kolekcje Eclipse.

Nikhil Nanivadekar
źródło
2

Spróbuj tego:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));
Alper Karaağaçlı
źródło
Do Twojej wiadomości, jeśli robisz to na Androidzie, wymaga to co najmniej poziomu API 24
MSpeed
1

Jeśli twoje obiekty mają jakiegoś wspólnego przodka [niech tak będzie T], powinieneś użyć List<T>zamiast tego List<Object>i zaimplementować Komparator dla tego T, używając pola nazwy.

Jeśli nie masz wspólnego przodka, możesz zaimplementować Comperator i użyć odbicia, aby wyodrębnić nazwę. Zauważ, że użycie odbicia jest niebezpieczne, nie sugerowane i ma złe wyniki, ale umożliwia dostęp do nazwy pola nie wiedząc nic o rzeczywistym typie obiektu [poza tym, że ma pole z odpowiednią nazwą]

W obu przypadkach do sortowania należy użyć Collections.sort () .

dobrze
źródło
1

Znalazłem inny sposób na zrobienie tego typu.

if(listAxu.size() > 0){
    Collections.sort(listAxu, Comparator.comparing(IdentityNamed::getDescricao));
}
Rafael Mendes
źródło
0

To zakłada listę YourClasszamiast Object, jak wyjaśnił amit .

Możesz użyć tego bitu z biblioteki Google Guava:

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

Pozostałe wymienione odpowiedzi Comparatornie są błędne, ponieważ Orderingnarzędzia Comparator. To rozwiązanie jest moim zdaniem trochę łatwiejsze, chociaż może być trudniejsze, jeśli jesteś początkującym i nie jesteś przyzwyczajony do korzystania z bibliotek i / lub „programowania funkcjonalnego”.

Bezwstydnie skopiowałem tę odpowiedź na moje własne pytanie.

Bart van Heukelom
źródło
To jest sposób, w jaki bym to zrobił, ale może to być za dużo dla OP.
Greg Case,
0

Korzystanie z wyboru Sortuj

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;

}
Shizumaru18
źródło
(1) Dlaczego miałby wymyślać koło na nowo? Co w tym złego Collections.sort()? (2) lista jest typu List<Object>i dlatego list.get(j).getName()nie zostanie skompilowana. (3) to rozwiązanie to O (n ^ 2), podczas gdy użycie Collections.sort()jest lepszym rozwiązaniem O (nlogn).
amit
0

Jeśli używasz a List<Object>do przechowywania obiektów podtypu, który ma pole nazwy (nazwijmy podtyp NamedObject), będziesz musiał obniżyć elementy listy, aby uzyskać dostęp do nazwy. Masz 3 opcje, z których najlepsza jest pierwsza:

  1. Nie używaj List<Object>w pierwszej kolejności a, jeśli możesz temu pomóc - zachowaj nazwane obiekty w aList<NamedObject>
  2. Skopiuj swoje List<Object>elementy do pliku List<NamedObject>, w trakcie zmniejszania, posortuj, a następnie skopiuj je z powrotem
  3. Zrób downcasting w Komparatorze

Opcja 3 wyglądałaby tak:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}
Mike E.
źródło
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
źródło
1
Chcesz rozwinąć, a nie tylko porzucić kod w pytaniu sprzed 3 lat?
Holloway
0

Odpowiedź @ Victora zadziałała dla mnie i opublikowałem ją ponownie w Kotlinie na wypadek, gdyby była przydatna dla kogoś innego, kto robi Androida.

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
źródło