Компаратор Java, использующий .ReverseOrder(), но с внутренним классом

#java #sorting #comparable

#java #сортировка #сопоставимый

Вопрос:

Я создаю простую программу, чтобы узнать о классе Java Comparator. Я отсортировал Arraylist по порядку, но теперь я хочу отсортировать список в порядке убывания, но у меня возникли проблемы с тем, где вызвать .reverseOrder() метод, поскольку я использовал внутренний класс, который реализует Comparator<Song> (song — это класс song, в котором находятся методы получения и установки).

Вот мой SongSort класс, в котором находится процесс сортировки и т.д.;

 import java.util.*;
import java.io.*;

public class SongSort
{
    ArrayList<Song> songList = new ArrayList<Song>();

    public void main(String[] args)
    {
        new SongSort().go();
    }

    class ArtistCompare implements Comparator<Song>
    {
        public int compare(Song one, Song two)
        {
            return one.getRating().compareTo(two.getRating());
        }
    }


    public void go()
    {

        getSongs();
        System.out.println(songList);
        //Collections.sort(songList); 
        System.out.println(songList);

        ArtistCompare artistCompare = new ArtistCompare();
        Collections.sort(songList, artistCompare);
        System.out.println(songList);
    }



    public void getSongs()
    {
        try{
            File file = new File("SongListMore.txt");
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String line = null;

            while((line = reader.readLine()) != null)
               {
                   addSong(line);
               }
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
            }
        }

        public void addSong(String lineToParse)
        {
            String [] tokens = lineToParse.split("/");
            Song nextSong = new Song(tokens[0],  tokens[1], tokens[2], tokens[3]);
            songList.add(nextSong);

    }

}
  

И вот мой простой Song класс;

 public class Song //implements Comparable<Song>
{
    private String title;
    private String artist;
    private String rating;
    private String bpm;

    public Song(String t, String a, String r, String b)
    {
        title = t;
        artist = a;
        rating = r;
        bpm = b;
    }

    public String getTitle()
    {
        return title;
    }

    public String getArtist()
    {
        return artist;
    }
    public String getRating()
    {
        return rating;
    }
    public String getBpm()
    {
        return bpm;
    }

    public String toString()
    {
       return ("Title : "   title   ","    " Artist : "   artist    " Rating : "   rating);
    }
}
  

Кто-нибудь может помочь мне выяснить, где я буду вызывать reverseOrder() метод в SongSort классе, поскольку он не будет компилироваться?

Ответ №1:

 ArtistCompare artistCompare = new ArtistCompare();
Collections.sort(songList, Collections.reverseOrder(artistCompare));
  

Редактировать Июль 2015

Поскольку этот ответ все еще привлекает некоторое внимание, вот небольшое обновление:

С Java SE 8 становится проще создавать обратный компаратор:

 Comparator<Song> songRatingComparator = Comparator.comparing(Song::getRating);
Collections.sort(songList, songRatingComparator.reversed());
  

И вы, конечно, также можете использовать Streams framework:

 List<Song> sortedSongList = songList.stream()
.sorted(Comparator.comparing(Song::getRating).reversed())
.collect(Collectors.toList());
  

Комментарии:

1. Что, если я хочу создать компаратор по двум полям, по возрастанию двойного поля и по убыванию строкового поля?

2. @gstackoverflow Пожалуйста, взгляните на Javadoc. Существуют аналогичные методы для двойных свойств (comparingDouble, затем Comparingdouble), и есть перегруженные методы, в которые вы можете передавать другие компараторы, такие как ReverseOrder())

3. Вы можете сделать songList.sort(Comparator.comparing(Song::getRating).reversed()) , нет необходимости передавать его в потоковом режиме (если исходный список не является неизменяемым)

Ответ №2:

Одним из способов реализации компаратора обратного порядка является реализация делегата-компаратора, который инвертирует результат компаратора (путем изменения порядка).

 public class ReverseOrder<T> implements Comparator<T> {
  private Comparator<T> delegate;
  public ReverseOrder(Comparator<T> delegate){
    this.delegate = delegate;
  }

  public int compare(T a, T b) {
    //reverse order of a and b!!!
    return this.delegate.compare(b,a);
  }
}
  

Итак, единственное, что вам нужно сделать, это использовать этот делегат.
Например:

   Comparator myComparator = new myComparator();
  List list = ...;
  List reverse = new ArrayList(list);

  //acceding
  Collections.sort(list, myComparator);

  //descending
  Collections.sort(list, new ReverseOrder(myComparator));
  

Комментарии:

1. java.utils. Collections.ReverseOrder(Comparator c) сделает то же самое и инвертирует сравнение вашего компаратора. Поэтому вам не следует изобретать велосипед здесь, а использовать Java SE API.

2. Вот почему ответ Puce является принятым ответом. — В любом случае я не буду удалять этот ответ, потому что он является действительным.

3. Мне нравится этот ответ, потому что он более надежный, а компараторы имеют больше применений, чем сортировка существующих списков. Например, я смог использовать это в конструкции TreeMap (Comparator), которая является SortedMap.

Ответ №3:

Давайте возьмем простой пример, у нас есть класс Person с двумя полями name age, и мы хотим отсортировать существующую коллекцию людей на основе их возраста, поэтому давайте предположим, что у нас есть класс Person с конструктором и добавим людей в список, а затем отсортируем их, не используя метод sort of collection :

 Person bachiri = new Person (17,"bachiri");
Person taoufiq = new Person (14,"Taoufiq");
Person abderrahman = new Person (15,"abderrahman");
List<Person> persons =  new ArrayList<>();
  

и это это побуждение Agecomparable :

 class AgeComparator implements Comparator<Person>{


    @Override
    public int compare(Person person1, Person person2) {
        return Integer.compare(person1.getAge(),person2.getAge());
    }


}
  

хитрость заключается в том, чтобы умножить возвращаемый метод на -1, чтобы конечный результат был обратным:
класс AgeComparator реализует компаратор{

     @Override
    public int compare(Person person1, Person person2) {
        return -1 * Integer.compare(person1.getAge(),person2.getAge());
    }


}
  

итак, теперь мы можем получить обратный результат :

 Collection.sort (Persons, new AgeComparator());
  

Комментарии:

1. Я только что видел ответ @Ralph, что практично, вы можете переключать параметры a, b восьмеркой или писать return -1 *this.delegate.compare(a,b);

2.небольшая настройка @Override public int compare(Person person1, Person person2) { if (person1.getAge() == null || person2.getAge == null) { return 1; } return Integer.compare(person2.getAge(),person1.getAge()); }

Ответ №4:

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

 public class ComparatorInverse implements Comparator<Object> {
   @Override
   public int compare(Object lhs, Object rhs) {
      return -1;
   }
}
  

Комментарии:

1. Это неверно. Взгляните на Javadoc: docs.oracle.com/javase/7/docs/api/java/util /…

2. Возврат фиксированного значения, независимого от аргументов, вообще не имеет никакого смысла, не говоря уже о случае обратного порядка. Просто поменяйте местами аргументы, и теперь они упорядочены по-другому — это вообще не приведет к какому-либо стабильному порядку.

3. Я вижу, что я не сохраняю ограничения. Даже если это не имеет смысла, у меня это работает.

4. Я предполагаю, что в вашем коде вы сначала вставляете объекты в отсортированном порядке, в чем-то вроде ArrayList, который сохраняет порядок вставки. Теперь вызов sort в этом списке с помощью ComparatorInverse будет вызывать compare() фиксированным и предсказуемым образом всегда lhs < rhs . Затем возврат -1 изменяет этот порядок. Но если вы вставляете свои элементы (скажем, числа) случайным образом или алгоритм сортировки изменяется, это больше не приведет к правильному результату с точки зрения естественного способа сортировки чего бы то ни было Object .

5. Да, элементы в порядке — в моем решении я написал, чтобы изменить текущий порядок. Метод Collections.sort() вызовет сортировку слиянием, которая переключает все элементы в сортировке (возвращая значение -1). И, конечно, вы правы, если они изменят алгоритм сортировки, это может все испортить 🙂 — так что это неверно.