다른 시간에 다른 변수로 목록을 정렬하는 방법
Person
예를 들어 여러 속성으로 명명 된 클래스가 있습니다 .
public class Person {
private int id;
private String name, address;
// Many more properties.
}
많은 Person
-object가 ArrayList<Person>
. 이 목록을 여러 개의 정렬하고, 정렬 변수입니다. 를 들어 한 예 번은 name
오름차순과 address
내림차순 으로 정렬 하고 다른 time-에는 내림차순 으로 정렬하고 싶을 수 있습니다 id
.
그리고 나만의 정렬 방법을 만들고 싶지 않습니다 (예 :를 사용하고 싶습니다 Collections.sort(personList, someComparator)
.이를 달성하는 가장 우아한 솔루션은 무엇입니까?
enum 접근 방식은 기본적으로 건전 앞에 생각하지만 스위치 문에는 더 많은 접근 방식은 접근 방식이 필요합니다. 치다 :
enum PersonComparator implements Comparator<Person> {
ID_SORT {
public int compare(Person o1, Person o2) {
return Integer.valueOf(o1.getId()).compareTo(o2.getId());
}},
NAME_SORT {
public int compare(Person o1, Person o2) {
return o1.getFullName().compareTo(o2.getFullName());
}};
public static Comparator<Person> decending(final Comparator<Person> other) {
return new Comparator<Person>() {
public int compare(Person o1, Person o2) {
return -1 * other.compare(o1, o2);
}
};
}
public static Comparator<Person> getComparator(final PersonComparator... multipleOptions) {
return new Comparator<Person>() {
public int compare(Person o1, Person o2) {
for (PersonComparator option : multipleOptions) {
int result = option.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
};
}
}
사용 예 (정적 가져 오기 오기 사용).
public static void main(String[] args) {
List<Person> list = null;
Collections.sort(list, decending(getComparator(NAME_SORT, ID_SORT)));
}
정렬하려는 각 속성에 대한 비교기를 만든 다음 다음과 같이 "비교 자 연결"을 시도 할 수 있습니다. :-)
public class ChainedComparator<T> implements Comparator<T> {
private List<Comparator<T>> simpleComparators;
public ChainedComparator(Comparator<T>... simpleComparators) {
this.simpleComparators = Arrays.asList(simpleComparators);
}
public int compare(T o1, T o2) {
for (Comparator<T> comparator : simpleComparators) {
int result = comparator.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
}
한 가지 방법은 Comparator
이 예제에서 볼 수있는 정렬 할 속성 목록을 인수로 사용하는 것을 만드는 것 입니다.
public class Person {
private int id;
private String name, address;
public static Comparator<Person> getComparator(SortParameter... sortParameters) {
return new PersonComparator(sortParameters);
}
public enum SortParameter {
ID_ASCENDING, ID_DESCENDING, NAME_ASCENDING,
NAME_DESCENDING, ADDRESS_ASCENDING, ADDRESS_DESCENDING
}
private static class PersonComparator implements Comparator<Person> {
private SortParameter[] parameters;
private PersonComparator(SortParameter[] parameters) {
this.parameters = parameters;
}
public int compare(Person o1, Person o2) {
int comparison;
for (SortParameter parameter : parameters) {
switch (parameter) {
case ID_ASCENDING:
comparison = o1.id - o2.id;
if (comparison != 0) return comparison;
break;
case ID_DESCENDING:
comparison = o2.id - o1.id;
if (comparison != 0) return comparison;
break;
case NAME_ASCENDING:
comparison = o1.name.compareTo(o2.name);
if (comparison != 0) return comparison;
break;
case NAME_DESCENDING:
comparison = o2.name.compareTo(o1.name);
if (comparison != 0) return comparison;
break;
case ADDRESS_ASCENDING:
comparison = o1.address.compareTo(o2.address);
if (comparison != 0) return comparison;
break;
case ADDRESS_DESCENDING:
comparison = o2.address.compareTo(o1.address);
if (comparison != 0) return comparison;
break;
}
}
return 0;
}
}
}
그런 다음 다음과 같은 코드에서 사용할 수 있습니다.
cp = Person.getComparator(Person.SortParameter.ADDRESS_ASCENDING,
Person.SortParameter.NAME_DESCENDING);
Collections.sort(personList, cp);
한 가지 접근 방식은 Comparator
의 를 작성하는을 구석으로 입니다. 이 라이브러리 메서드 일 수 있습니다 (저기 어딘가에 존재 확신합니다).
public static <T> Comparator<T> compose(
final Comparator<? super T> primary,
final Comparator<? super T> secondary
) {
return new Comparator<T>() {
public int compare(T a, T b) {
int result = primary.compare(a, b);
return result==0 ? secondary.compare(a, b) : result;
}
[...]
};
}
사용하다 :
Collections.sort(people, compose(nameComparator, addressComparator));
또는 Collections.sort
누르십시오. 성능이 절대적으로 중요하지 않은 경우 기본 순서보다 2 차 순서로 정렬됩니다.
Collections.sort(people, addressComparator);
Collections.sort(people, nameComparator);
비교를 사용하면 매우 독립적으로 할 수 있습니다. Person 클래스 자체 또는 필요와 관련된 서비스 클래스에서 비교기의 단일 인스턴스를 만들 수 있습니다.
익명 내부 클래스를 사용하는 예 :
public static final Comparator<Person> NAME_ASC_ADRESS_DESC
= new Comparator<Person>() {
public int compare(Person p1, Person p2) {
int nameOrder = p1.getName().compareTo(p2.getName);
if(nameOrder != 0) {
return nameOrder;
}
return -1 * p1.getAdress().comparedTo(p2.getAdress());
// I use explicit -1 to be clear that the order is reversed
}
};
public static final Comparator<Person> ID_DESC
= new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return -1 * p1.getId().comparedTo(p2.getId());
// I use explicit -1 to be clear that the order is reversed
}
};
// and other comparator instances as needed...
경우 많은 원하는 방식으로 비교기 코드를 구성 할 수도 있습니다 . 예를 들어 다음과 같이 할 수 있습니다.
- 다른 비교기에서 상속,
- 기존 비교를 가지고있는 CompositeComparator가 있습니다.
- null 케이스를 처리하는 NullComparator가 있고 다른 비교기에
- 기타 ...
나는 당신의 대답과 같이 분류기를 사람 클래스에 결합하는 좋은 생각이 아니라고 생각합니다. 왜냐하면 그것은 비교 (일반적으로 비즈니스 중심)와 모델이 서로 가깝게 결합하기 때문입니다. 분류기에서 작업을 변경 / 추가하고 싶을 때마다 사람 클래스를 터치해야합니다. 일반적으로 활동하는 일입니다.
KLE가 제안한 것과 동일한 비교기 인스턴스를 사용하는 서비스 또는 이와 동일한 것을 사용하면 훨씬 유연하고 확장 할 수 있습니다.
내 접근 방식은 Yishai를 기반으로합니다. 가장 큰 차이는 속성에 대해 먼저 오름차순으로 정렬하고 그 후에 나중에 속성에 대해 내림차순으로 정렬하는 방법이 있습니다. 열거 형 수행 수행 할 수 없습니다. 그것을 위해 나는 수업을 사용했습니다. SortOrder는 내부 클래스로 구현하기를 선호하는 유형에 의존하기 때문입니다.
내부 클래스가 'SortOrder'인 'Person'클래스 :
import java.util.Comparator;
public class Person {
private int id;
private String firstName;
private String secondName;
public Person(int id, String firstName, String secondName) {
this.id = id;
this.firstName = firstName;
this.secondName = secondName;
}
public abstract static class SortOrder implements Comparator<Person> {
public static SortOrder PERSON_ID = new SortOrder() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getId()).compareTo(p2.getId());
}
};
public static SortOrder PERSON_FIRST_NAME = new SortOrder() {
public int compare(Person p1, Person p2) {
return p1.getFirstName().compareTo(p2.getFirstName());
}
};
public static SortOrder PERSON_SECOND_NAME = new SortOrder() {
public int compare(Person p1, Person p2) {
return p1.getSecondName().compareTo(p2.getSecondName());
}
};
public static SortOrder invertOrder(final SortOrder toInvert) {
return new SortOrder() {
public int compare(Person p1, Person p2) {
return -1 * toInvert.compare(p1, p2);
}
};
}
public static Comparator<Person> combineSortOrders(final SortOrder... multipleSortOrders) {
return new Comparator<Person>() {
public int compare(Person p1, Person p2) {
for (SortOrder personComparator: multipleSortOrders) {
int result = personComparator.compare(p1, p2);
if (result != 0) {
return result;
}
}
return 0;
}
};
}
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getSecondName() {
return secondName;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append("Person with id: ");
result.append(id);
result.append(" and firstName: ");
result.append(firstName);
result.append(" and secondName: ");
result.append(secondName);
result.append(".");
return result.toString();
}
}
Person 클래스와 그 SortOrder를 사용하는 예 :
import static multiplesortorder.Person.SortOrder.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import multiplesortorder.Person;
public class Application {
public static void main(String[] args) {
List<Person> listPersons = new ArrayList<Person>(Arrays.asList(
new Person(0, "...", "..."),
new Person(1, "...", "...")
));
Collections.sort(listPersons, combineSortOrders(PERSON_FIRST_NAME, invertOrder(PERSON_ID)));
for (Person p: listPersons) {
System.out.println(p.toString());
}
}
}
오 루무
최근에 여러 필드를 정렬하기 위해 비교를 작성했습니다. 구분 기호, 레코드 구조 및 정렬 규칙 (일부는 유형별)을 정의 할 수 있습니다. 개인 레코드는 구분 된 코드로 변환하여이를 사용할 수 있습니다.
필수 정보는 프로그래밍 방식으로 또는 XML 파일을 통해 비교기 자체에 시드됩니다.
XML은 패키지에 포함 된 XSD 파일에 의해 유효성이 검사됩니다. 예를 들어, 아래는 4 개의 필드 (이 중 2 개는 정렬 가능)가있는 탭으로 구분 된 레코드 레이아웃입니다.
<?xml version="1.0" encoding="ISO-8859-1"?>
<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<delimiter>	</delimiter>
<column xsi:type="Decimal">
<name>Column One</name>
</column>
<column xsi:type="Integer">
<name>Column Two</name>
</column>
<column xsi:type="String">
<name>Column Three</name>
<sortOrder>2</sortOrder>
<trim>true</trim>
<caseSensitive>false</caseSensitive>
<stripAccents>true</stripAccents>
</column>
<column xsi:type="DateTime">
<name>Column Four</name>
<sortOrder>1</sortOrder>
<ascending>true</ascending>
<nullLowSortOrder>true</nullLowSortOrder>
<trim>true</trim>
<pattern>yyyy-MM-dd</pattern>
</column>
</row>
그런 다음 Java에서 다음과 같이 사용합니다.
Comparator<String> comparator = new RowComparator(
new XMLStructureReader(new File("layout.xml")));
도서관은 여기에서 찾을 수 있습니다 :
http://sourceforge.net/projects/multicolumnrowcomparator/
클래스 Coordinate
가 있고 X 좌표와 Y 좌표에 따라 두 가지 방식으로 분류해야 한다고 가정합니다 . 이를 위해서는 두 개의 다른 비교기가 필요합니다. 아래는 샘플입니다
class Coordinate
{
int x,y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
static Comparator<Coordinate> getCoordinateXComparator() {
return new Comparator<Coordinate>() {
@Override
public int compare(Coordinate Coordinate1, Coordinate Coordinate2) {
if(Coordinate1.x < Coordinate2.x)
return 1;
else
return 0;
}
// compare using Coordinate x
};
}
static Comparator<Coordinate> getCoordinateYComparator() {
return new Comparator<Coordinate>() {
@Override
public int compare(Coordinate Coordinate1, Coordinate Coordinate2) {
if(Coordinate1.y < Coordinate2.y)
return 1;
else
return 0;
}
// compare using Coordinate y
};
}
}
'IT' 카테고리의 다른 글
전체 화면 Java의 JFrame (0) | 2020.08.27 |
---|---|
한 활동의 값을 이전 활동으로 전달하는 방법 (0) | 2020.08.27 |
akka는 Erlang과 어떻게 비교 검증? (0) | 2020.08.27 |
PDB 중단 점을 Python 코드에 넣는 더 간단한 방법? (0) | 2020.08.27 |
전환이 끝날 때 호출 (0) | 2020.08.27 |