[java] Java에서 두 필드를 기준으로 정렬하는 방법은 무엇입니까?

객체 배열이 있습니다 person (int age; String name;).

이 배열을 알파벳순으로 이름순으로 정렬 한 다음 어떻게 연령 순으로 정렬 할 수 있습니까?

어떤 알고리즘을 사용 하시겠습니까?



답변

Collections.sort다음과 같이 사용할 수 있습니다 .

private static void order(List<Person> persons) {

    Collections.sort(persons, new Comparator() {

        public int compare(Object o1, Object o2) {

            String x1 = ((Person) o1).getName();
            String x2 = ((Person) o2).getName();
            int sComp = x1.compareTo(x2);

            if (sComp != 0) {
               return sComp;
            }

            Integer x1 = ((Person) o1).getAge();
            Integer x2 = ((Person) o2).getAge();
            return x1.compareTo(x2);
    }});
}

List<Persons> 이제 이름, 나이별로 정렬됩니다.

String.compareTo문서 에서 두 개의 문자열을 사전 식으로 비교합니다 .”

Collections.sort네이티브 콜렉션 라이브러리의 정적 메소드입니다. 실제 정렬을 수행하므로 목록의 두 요소를 비교하는 방법을 정의하는 Comparator를 제공하면 compare됩니다.


답변

Java 8 스트리밍 API를 사용할 수있는 사람들을 위해 여기에 잘 정리 된 깔끔한 접근 방식이 있습니다 :
Lambdas 및 정렬

C # LINQ와 동등한 것을 찾고있었습니다.

.ThenBy(...)

비교기에서 Java 8의 메커니즘을 찾았습니다.

.thenComparing(...)

알고리즘을 보여주는 스 니펫은 다음과 같습니다.

    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));

더 깔끔한 방법과 위의 링크를 확인하여 Java의 형식 유추가 LINQ와 비교하여 정의하기가 조금 더 어색한 방법에 대한 설명을 확인하십시오.

참조를위한 전체 단위 테스트는 다음과 같습니다.

@Test
public void testChainedSorting()
{
    // Create the collection of people:
    ArrayList<Person> people = new ArrayList<>();
    people.add(new Person("Dan", 4));
    people.add(new Person("Andi", 2));
    people.add(new Person("Bob", 42));
    people.add(new Person("Debby", 3));
    people.add(new Person("Bob", 72));
    people.add(new Person("Barry", 20));
    people.add(new Person("Cathy", 40));
    people.add(new Person("Bob", 40));
    people.add(new Person("Barry", 50));

    // Define chained comparators:
    // Great article explaining this and how to make it even neater:
    // http://blog.jooq.org/2014/01/31/java-8-friday-goodies-lambdas-and-sorting/
    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));

    // Sort the stream:
    Stream<Person> personStream = people.stream().sorted(comparator);

    // Make sure that the output is as expected:
    List<Person> sortedPeople = personStream.collect(Collectors.toList());
    Assert.assertEquals("Andi",  sortedPeople.get(0).name); Assert.assertEquals(2,  sortedPeople.get(0).age);
    Assert.assertEquals("Barry", sortedPeople.get(1).name); Assert.assertEquals(20, sortedPeople.get(1).age);
    Assert.assertEquals("Barry", sortedPeople.get(2).name); Assert.assertEquals(50, sortedPeople.get(2).age);
    Assert.assertEquals("Bob",   sortedPeople.get(3).name); Assert.assertEquals(40, sortedPeople.get(3).age);
    Assert.assertEquals("Bob",   sortedPeople.get(4).name); Assert.assertEquals(42, sortedPeople.get(4).age);
    Assert.assertEquals("Bob",   sortedPeople.get(5).name); Assert.assertEquals(72, sortedPeople.get(5).age);
    Assert.assertEquals("Cathy", sortedPeople.get(6).name); Assert.assertEquals(40, sortedPeople.get(6).age);
    Assert.assertEquals("Dan",   sortedPeople.get(7).name); Assert.assertEquals(4,  sortedPeople.get(7).age);
    Assert.assertEquals("Debby", sortedPeople.get(8).name); Assert.assertEquals(3,  sortedPeople.get(8).age);
    // Andi     : 2
    // Barry    : 20
    // Barry    : 50
    // Bob      : 40
    // Bob      : 42
    // Bob      : 72
    // Cathy    : 40
    // Dan      : 4
    // Debby    : 3
}

/**
 * A person in our system.
 */
public static class Person
{
    /**
     * Creates a new person.
     * @param name The name of the person.
     * @param age The age of the person.
     */
    public Person(String name, int age)
    {
        this.age = age;
        this.name = name;
    }

    /**
     * The name of the person.
     */
    public String name;

    /**
     * The age of the person.
     */
    public int age;

    @Override
    public String toString()
    {
        if (name == null) return super.toString();
        else return String.format("%s : %d", this.name, this.age);
    }
}


답변

Java 8 스트림 접근 방식 사용 …

//Creates and sorts a stream (does not sort the original list)       
persons.stream().sorted(Comparator.comparing(Person::getName).thenComparing(Person::getAge));

그리고 Java 8 Lambda 접근 방식은 …

//Sorts the original list Lambda style
persons.sort((p1, p2) -> {
        if (p1.getName().compareTo(p2.getName()) == 0) {
            return p1.getAge().compareTo(p2.getAge());
        } else {
            return p1.getName().compareTo(p2.getName());
        }
    });

마지막으로 …

//This is similar SYNTAX to the Streams above, but it sorts the original list!!
persons.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));


답변

당신은 당신 자신을 구현 Comparator하고 그것을 사용해야합니다 : 예를 들어

Arrays.sort(persons, new PersonComparator());

비교기는 다음과 같이 보일 수 있습니다.

public class PersonComparator implements Comparator<? extends Person> {

  public int compare(Person p1, Person p2) {
     int nameCompare = p1.name.compareToIgnoreCase(p2.name);
     if (nameCompare != 0) {
        return nameCompare;
     } else {
       return Integer.valueOf(p1.age).compareTo(Integer.valueOf(p2.age));
     }
  }
}

비교기는 먼저 이름을 비교하고, 같지 않으면 비교 결과를 반환하고, 그렇지 않으면 두 사람의 나이를 비교할 때 비교 결과를 반환합니다.

이 코드는 초안 일뿐입니다. 클래스는 불변이기 때문에 단일 정렬을 만드는 대신 각 정렬에 대해 새 인스턴스를 만드는 것을 생각할 수 있습니다.


답변

이를 위해 Java 8 Lambda 접근 방식을 사용할 수 있습니다. 이처럼 :

persons.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));


답변

person 클래스가 Comparable<Person>다음과 같이 compareTo 메소드를 구현 한 다음 구현하십시오.

public int compareTo(Person o) {
    int result = name.compareToIgnoreCase(o.name);
    if(result==0) {
        return Integer.valueOf(age).compareTo(o.age);
    }
    else {
        return result;
    }
}

먼저 이름 (대소 문자 구분)으로 정렬 한 다음 나이별로 정렬합니다. 그런 다음 실행할 수 있습니다 Arrays.sort()또는 Collections.sort()사람 개체의 컬렉션 또는 배열에.


답변

구아바 ComparisonChain는 깔끔한 방법을 제공합니다. 이 링크를 참조하십시오 .

체인 비교문을 수행하기위한 유틸리티입니다. 예를 들면 다음과 같습니다.

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(this.aString, that.aString)
         .compare(this.anInt, that.anInt)
         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
         .result();
   }