2012-05-22 5 views
17

Я пытаюсь изучить компаратор в java, и я нашел этот отличный пример онлайн, мой вопрос заключается в том, как изменить этот код, чтобы имена животных упорядочивались по возрасту и в порядке убывания, так что самый старый является первым, а младший - последним ?Java-компаратор, как сортировать по целому числу?

class Dog implements Comparator<Dog>, Comparable<Dog>{ 
private String name; 
private int age; 
Dog(){ 
} 

Dog(String n, int a){ 
    name = n; 
    age = a; 
} 

public String getDogName(){ 
    return name; 
} 

public int getDogAge(){ 
    return age; 
} 

// Overriding the compareTo method 
public int compareTo(Dog d){ 
    return (this.name).compareTo(d.name); 
} 

// Overriding the compare method to sort the age 
public int compare(Dog d, Dog d1){ 
    return d.age - d1.age; 
} 
} 

public class Example{ 
public static void main(String args[]){ 
    // Takes a list o Dog objects 
    List<Dog> list = new ArrayList<Dog>(); 

    list.add(new Dog("Shaggy",3)); 
    list.add(new Dog("Lacy",2)); 
    list.add(new Dog("Roger",10)); 
    list.add(new Dog("Tommy",4)); 
    list.add(new Dog("Tammy",1)); 
    Collections.sort(list);// Sorts the array list 

    for(Dog a: list)//printing the sorted list of names 
    System.out.print(a.getDogName() + ", "); 

    // Sorts the array list using comparator 
    Collections.sort(list, new Dog()); 
    System.out.println(" "); 
    for(Dog a: list)//printing the sorted list of ages 
    System.out.print(a.getDogName() +" : "+ 
    a.getDogAge() + ", "); 
} 
} 
+5

Это, безусловно, не является хорошим примером, используя одну собаку, чтобы сравнить возраст двух других невероятно плохой дизайн. Не имеет значения, является ли это всего лишь небольшим примером того, как это может работать. Это дает людям неправильные идеи о том, как правильно реализовать эти интерфейсы. – Cephalopod

ответ

72

Простое изменение

public int compare(Dog d, Dog d1) { 
    return d.age - d1.age; 
} 

в

public int compare(Dog d, Dog d1) { 
    return d1.age - d.age; 
} 

должны сортировать их в обратном порядке возраста, если это то, что вы ищете.

Update:

@Arian прав в своих комментариях, один из принятых способов объявить компаратор для собаки будет где вы объявляете его в качестве общественного статического конечного поля в самом классе.

class Dog implements Comparable<Dog> { 
    private String name; 
    private int age; 

    public static final Comparator<Dog> DESCENDING_COMPARATOR = new Comparator<Dog>() { 
     // Overriding the compare method to sort the age 
     public int compare(Dog d, Dog d1) { 
      return d.age - d1.age; 
     } 
    }; 

    Dog(String n, int a) { 
     name = n; 
     age = a; 
    } 

    public String getDogName() { 
     return name; 
    } 

    public int getDogAge() { 
     return age; 
    } 

    // Overriding the compareTo method 
    public int compareTo(Dog d) { 
     return (this.name).compareTo(d.name); 
    } 

} 

Вы могли бы использовать его в любом месте вашего кода, где вы хотели бы сравнить собак следующим образом:

// Sorts the array list using comparator 
Collections.sort(list, Dog.DESCENDING_COMPARATOR); 

Еще одна важная вещь, чтобы помнить при осуществлении Сопоставимые является то, что это очень важно, что CompareTo выполняет последовательно с равными. Хотя это и не требуется, неспособность сделать это может привести к странному поведению в некоторых коллекциях, таких как некоторые реализации наборов. См. Сообщение this для получения дополнительной информации о разумных принципах реализации compareTo.

Обновление 2: Крис прав, этот код подвержен переполнениям для больших отрицательных значений возраста. Правильный способ реализовать это в Java 7 и выше будет Integer.compare(d.age, d1.age) вместо d.age - d1.age.

+3

Здесь вряд ли будет представлять проблему, но в этом компараторе есть ошибка с переполнением/недополнением целого числа. Если возраст собак - «Integer.MIN_VALUE» и любое положительное целое число (или «Integer.MAX_VALUE» и любое отрицательное число), вы получите обертку и порядок сортировки будет неожиданным. Это кажется глупым, но это то, о чем я думаю, что программисты должны думать, даже если сравнивать возрасты собак. Попробуйте использовать 'Integer.compare' (и другие подобные методы в других подклассах java.lang.Number) вместо выполнения собственного вычитания. –

18

Просто замените:

return d.age - d1.age; 

By:

return ((Integer)d.age).compareTo(d1.age); 

Или инвертировать, чтобы полностью изменить список:

return ((Integer)d1.age).compareTo(d.age); 

EDIT:

Исправлена ​​проблема с памятью.
Действительно, лучшим решением является изменение age поля в Dog класса Integer, потому что там много преимуществ, как null возможность ...

+3

За счет ненужного создания объектов. Не делайте этого для больших наборов данных, когда вам достаточно много сортировать. В частности, поскольку альтернатива намного проще ... –

+1

По крайней мере, используйте 'Integer.valueOf()' вместо 'new' – Cephalopod

+4

Почему бы просто не использовать' return Integer.compare (d.age, d1.age); '? Доступно с Java 7 – McIntosh

4

Один простой способ

Comparator<Dog> ageAscendingComp = ...; 
Comparator<Dog> ageDescendingComp = Collections.reverseOrder(ageAscendingComp); 
// then call the sort method 

На стороне записки , Собака должна действительно не применять Comparator.Это означает, что вам нужно делать такие странные вещи, как

Collections.sort(myList, new Dog("Rex", 4)); 
// ^-- why is a new dog being made? What are we even sorting by?! 
Collections.sort(myList, myList.get(0)); 
// ^-- or perhaps more confusingly 

Скорее вы должны сделать Compartors отдельным классом.

например.

public class DogAgeComparator implments Comparator<Dog> { 
    public int compareTo(Dog d1, Dog d2) { 
     return d1.getAge() - d2.getAge(); 
    } 
} 

Это имеет дополнительное преимущество, что вы можете использовать имя класса, чтобы сказать, как компаратор будет сортировать список. например.

Collections.sort(someDogs, new DogNameComparator()); 
// now in name ascending order 

Collections.sort(someDogs, Collections.reverseOrder(new DogAgeComparator())); 
// now in age descending order 

Вы не должны также не иметь собак реализовать Comparable. Интерфейс Comparable используется для обозначения того, что существует некоторый естественный и естественный способ упорядочения этих объектов (например, для чисел и строк). Теперь это не относится к объектам Dog, поскольку иногда вы можете сортировать по возрасту, а иногда вы можете сортировать по имени.

11
public class DogAgeComparator implements Comparator<Dog> { 
    public int compare(Dog o1, Dog o2) { 
     return Integer.compare(o1.getAge(), o2.getId()); 
    } 
} 
+3

Не могли бы вы подробнее рассказать о своем ответе, добавив немного больше описания о предоставляемом вами решении? – abarisone

+2

Я полагаю, вы имеете в виду 'Integer.compare (o1.getDogAge(), o2.getDogAge())'? Класс Dog's Dog не имеет 'getAge', а идентификатор вычитания из возраста не имеет смысла. –

+3

Этот код требует минимального уровня API 19 из-за Integer.compare (o1.getAge(), o2.getId()). Если вы хотите использовать его на более низких уровнях API, вы можете использовать o1.getAge() - o2.getAge() instade – Sniper

1

Если у вас есть доступ к Java 8 Comparable API, может быть полезным Comparable.comparingToInt(). (См. Java 8 Comparable Documentation).

Например, Comparator<Dog> сортировать Dog экземпляров нисходящих по возрасту могут быть созданы с помощью следующих действий:

Comparable.comparingToInt(Dog::getDogAge).reversed();

Функции взять отображение лямбды T к Integer, и создает восходящий компаратор. Привязанная функция .reversed() превращает восходящий компаратор в нисходящий компаратор.

Примечание: хотя это может быть непригодно для большинства версий Android, я столкнулся с этим вопросом, ища аналогичную информацию для приложения, отличного от Android Java. Я думал, что это может быть полезно для других в том же месте, чтобы увидеть, что я в итоге решил.

4

С Java 8 вы можете использовать:

Comparator.comparingInt(Dog::getDogAge).reversed(); 
Смежные вопросы