( Java'daki nesne listelerini birden çok alana göre sıralamanın yolları )
Bu özette çalışma kodu
Java 8 lambda's'ı kullanma (10 Nisan 2019'da eklendi)
Java 8 bunu lambdalar tarafından güzel bir şekilde çözüyor (Guava ve Apache Commons yine de daha fazla esneklik sunabilir):
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
@ Gaoagong'un cevabı için teşekkürler .
Dağınık ve kıvrımlı: Elle sıralama
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
int sizeCmp = p1.size.compareTo(p2.size);
if (sizeCmp != 0) {
return sizeCmp;
}
int nrOfToppingsCmp = p1.nrOfToppings.compareTo(p2.nrOfToppings);
if (nrOfToppingsCmp != 0) {
return nrOfToppingsCmp;
}
return p1.name.compareTo(p2.name);
}
});
Bu çok fazla yazma, bakım gerektirir ve hataya açıktır.
Yansıtıcı yol: BeanComparator ile sıralama
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Açıkçası bu daha özlüdür, ancak bunun yerine Dizeler'i kullanarak alanlara doğrudan referansınızı kaybettiğiniz için daha fazla hata eğilimi vardır (yazım güvenliği, otomatik yeniden düzenleme yok). Şimdi bir alan yeniden adlandırılırsa, derleyici bir sorun bile bildirmez. Dahası, bu çözüm yansıma kullandığından, sıralama çok daha yavaştır.
Ulaşım: Google Guava'nın Karşılaştırma Zinciri ile Sıralama
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
return ComparisonChain.start().compare(p1.size, p2.size).compare(p1.nrOfToppings, p2.nrOfToppings).compare(p1.name, p2.name).result();
// or in case the fields can be null:
/*
return ComparisonChain.start()
.compare(p1.size, p2.size, Ordering.natural().nullsLast())
.compare(p1.nrOfToppings, p2.nrOfToppings, Ordering.natural().nullsLast())
.compare(p1.name, p2.name, Ordering.natural().nullsLast())
.result();
*/
}
});
Bu çok daha iyidir, ancak en yaygın kullanım durumu için bazı kazan plakası kodu gerektirir: null değerleri varsayılan olarak daha az değer verilmelidir. Boş alanlar için, bu durumda ne yapılacağı konusunda Guava'ya ekstra bir yönerge sağlamanız gerekir. Belirli bir şey yapmak istiyorsanız, ancak genellikle varsayılan durumu (yani 1, a, b, z, null) istiyorsanız bu esnek bir mekanizmadır.
Apache Commons ile Sıralama
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
return new CompareToBuilder().append(p1.size, p2.size).append(p1.nrOfToppings, p2.nrOfToppings).append(p1.name, p2.name).toComparison();
}
});
Guava'nın CompareisonChain'i gibi, bu kütüphane sınıfı da birden çok alanda kolayca sıralanır, ancak null değerler için varsayılan davranışı da tanımlar (örn. 1, a, b, z, null). Ancak, kendi Karşılaştırıcınızı sağlamadığınız sürece başka bir şey belirtemezsiniz.
Böylece
Sonuçta lezzet ve esneklik ihtiyacı (Guava'nın Karşılaştırma Zinciri) ve özlü kod (Apache'nin CompareToBuilder) ile ilgilidir.
Bonus yöntemi
Ben güzel bir çözüm bulduğunu birleştirir birden karşılaştırıcılar öncelik sırasına göre CodeReview üzerinde bir de MultiComparator
:
class MultiComparator<T> implements Comparator<T> {
private final List<Comparator<T>> comparators;
public MultiComparator(List<Comparator<? super T>> comparators) {
this.comparators = comparators;
}
public MultiComparator(Comparator<? super T>... comparators) {
this(Arrays.asList(comparators));
}
public int compare(T o1, T o2) {
for (Comparator<T> c : comparators) {
int result = c.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
public static <T> void sort(List<T> list, Comparator<? super T>... comparators) {
Collections.sort(list, new MultiComparator<T>(comparators));
}
}
Tabii ki Apache Commons Koleksiyonlarının bunun için zaten bir faydası var:
ComparatorUtils.chainedComparator (comparatorCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));