So sortieren Sie eine Liste <Objekt> alphabetisch anhand des Felds Objektname

102

Ich habe eine Liste von Objekten wie. List<Object> pIch möchte diese Liste alphabetisch anhand des Felds Objektname sortieren. Das Objekt enthält 10 Felder und das Namensfeld ist eines davon.

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

Aber es gibt nichts wie String.compare ..?

Saurabh Kumar
quelle
3
Wie kommst du auf den Namen? - Objects haben keine Namen. Meinst du mit .toString()?
Matt Fenwick
object1und object2müssen vom Typ sein Campaign, und die Vergleichsfunktion ist object1.getName().compareTo(object2.getName()).
Bart van Heukelom
Sie mischen List<Object>und Comparator<Campaign>. Das kannst du nicht machen. Entweder Sie haben List<Object>und Comparator<Object>oder List<Campaign>undComparator<Campaign>
viktor

Antworten:

230

Aus Ihrem Code geht hervor, dass Ihr Code Comparatorbereits mit parametriert ist Campaign. Dies funktioniert nur mit List<Campaign>. Die gesuchte Methode ist auch 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());
      }
  });
}

Oder wenn Sie Java 1.8 verwenden

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

Ein letzter Kommentar - es macht keinen Sinn, die Listengröße zu überprüfen. Die Sortierung funktioniert für eine leere Liste.

Robert B.
quelle
2
Ich denke, dies ist die beste Antwort, die alles in das zerlegt, wonach das OP sucht. Und aus den Kommentaren geht hervor, dass er die Groß- und Kleinschreibung nicht berücksichtigen möchte. Wechseln Sie also einfach den Vergleich zu "Vergleich zu ToIgnoreCase
Greg",
Kleinere Verbesserung in der ersten Lösung: Wir können tun, wenn (list.size ()> 1) - wie für 1 Artikel keine Notwendigkeit zu sortieren ..
Rami Yampolsky
12
Sie können verwendenComparator.comparing(Campaign::getName)
Jose Da Silva
4
list.sort((object1, object2) -> object1. getName().compareTo(object2. getName()));arbeitete für mich
Lucas
1
Versuchen Sie es mit sortedList = list.stream().sort((object1, object2) -> object1. getName().compareTo(object2. getName()))..collect(Collectors.toList());, um eine neue sortierte Liste zu erhalten
Lukas
16

CollatorAufgrund der Internationalisierung ist die Verwendung alphabetischer Zeichenfolgen die korrekteste Methode . Einige Sprachen haben aufgrund weniger zusätzlicher Zeichen usw. eine andere Reihenfolge.

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

Wenn Sie sich nicht für Internationalisierung interessieren, verwenden Sie 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
quelle
11

Schauen Sie sich Collections.sort()die ComparatorBenutzeroberfläche an.

Der String-Vergleich kann mit object1.getName().compareTo(object2.getName())oder erfolgen object2.getName().compareTo(object1.getName())(abhängig von der gewünschten Sortierrichtung).

Wenn Sie möchten, dass die Sortierung fallunabhängig ist, tun Sie dies object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase()).

Tobiasbayer
quelle
und wie schlagen Sie vor, das aufgerufene Feld namaaus dem ObjectTyp zu extrahieren ? Diese Antwort ist nicht vollständig.
Amit
Die Namensextraktion hängt vom Typ des Objekts ab. Ich nahm an, dass es nur ein Platzhaltertyp ist. Wenn Sie keinen konkreteren Typ angeben können, können Sie die Reflexion beenden.
Tobiasbayer
9

Verwenden von Java 8 Comparator.Vergleichen :

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

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

}

Bitte ersetzen Sie Object durch Ihre Klasse, die das Namensfeld enthält

Verwendung:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);
Jan Vorcak
quelle
Ich habe dies getan, aber dann kommt "Tests" vor "Suche" .: (((
Saurabh Kumar
wenn Sie o wollen Reverse Sortierung, ersetzen Sie einfach obj1.getName().compareTo(obj2.getName()mit obj2.getName().compareTo(obj1.getName()in der Vergleichsklasse
Jan Vorcak
2

etwas wie

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

Hier ist eine Version der Antwort von Robert B, List<T>die mit Reflection und ohne Bibliotheken von Drittanbietern für eine bestimmte String-Eigenschaft des Objekts funktioniert und diese sortiert

/**
 * 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
quelle
2

Sie können sortThisBy()aus Eclipse-Sammlungen verwenden :

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

Wenn Sie den Listentyp nicht ändern können von List:

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

Hinweis: Ich bin ein Mitarbeiter von Eclipse Collections.

Nikhil Nanivadekar
quelle
2

Versuche dies:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));
Alper Karaağaçlı
quelle
Zu Ihrer Information, wenn Sie dies in Android tun, erfordert es mindestens API-Level 24
MSpeed
1

Wenn Ihre Objekte einen gemeinsamen Vorfahren haben, sollten TSie List<T>stattdessen List<Object>einen Komparator für dieses T verwenden und mithilfe des Namensfelds implementieren .

Wenn Sie keinen gemeinsamen Vorfahren haben, können Sie einen Comperator implementieren und Reflection verwenden , um den Namen zu extrahieren. Beachten Sie, dass die Verwendung von Reflection unsicher und nicht empfehlenswert ist und unter einer schlechten Leistung leidet. Sie können jedoch auf einen Feldnamen zugreifen ohne etwas über den tatsächlichen Typ des Objekts zu wissen [abgesehen von der Tatsache, dass es ein Feld mit dem entsprechenden Namen hat]

In beiden Fällen sollten Sie Collections.sort () zum Sortieren verwenden.

amit
quelle
1

Ich habe einen anderen Weg gefunden, um den Typ zu machen.

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

Dies setzt eine Liste von YourClassstatt statt Object, wie von amit erklärt .

Sie können dieses Bit aus der Google Guava-Bibliothek verwenden:

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

Die anderen Antworten, die erwähnt werden, Comparatorsind nicht falsch, da Orderingimplementiert Comparator. Diese Lösung ist meiner Meinung nach etwas einfacher, obwohl es schwieriger sein kann, wenn Sie Anfänger sind und nicht daran gewöhnt sind, Bibliotheken und / oder "funktionale Programmierung" zu verwenden.

Schamlos von dieser Antwort auf meine eigene Frage kopiert .

Bart van Heukelom
quelle
So würde ich es machen, aber es könnte zu viel für das OP sein.
Greg Case
0

Verwenden einer Auswahl Sortieren

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
quelle
(1) Warum sollte er das Rad neu erfinden? Was ist los mit Collections.sort()? (2) Die Liste ist vom Typ List<Object>und wird daher list.get(j).getName()nicht kompiliert. (3) Diese Lösung ist O (n ^ 2), während die Verwendung Collections.sort()eine bessere O (nlogn) -Lösung ist.
Amit
0

Wenn Sie a verwenden List<Object>, um Objekte eines Subtyps mit einem NamedObjectNamensfeld zu speichern (nennen wir den Subtyp ), müssen Sie die Listenelemente herunterwerfen, um auf den Namen zugreifen zu können. Sie haben 3 Möglichkeiten, von denen die beste die erste ist:

  1. Verwenden Sie a erst gar nicht, List<Object>wenn Sie helfen können - bewahren Sie Ihre benannten Objekte in a aufList<NamedObject>
  2. Kopieren Sie Ihre List<Object>Elemente in ein List<NamedObject>Downcasting- Element , führen Sie die Sortierung durch und kopieren Sie sie dann zurück
  3. Führen Sie das Downcasting im Komparator durch

Option 3 würde folgendermaßen aussehen:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}
Mike E.
quelle
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
quelle
1
Möchten Sie in einer 3 Jahre alten Frage lieber Code ausarbeiten als nur ausgeben?
Holloway
0

@ Victors Antwort hat bei mir funktioniert und sie hier in Kotlin erneut veröffentlicht, falls sie für jemanden nützlich ist, der Android macht.

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
quelle