Diogo dos Santos
Diogo dos Santos

Reputation: 176

How can I sort a list that inside a map in Java?

I have a class that I created to store the results of a race, such as name and time of each driver, and I have determined that I wish the results to be compared based on the time.

public class Vysledek implements Comparable<Vysledek>{
private String jmeno;
private int hodina;
private int minuta;
private int sekunda;
    
public Vysledek(String jmeno, int h, int m, int s){
    if(jmeno==null)
        throw new IllegalArgumentException("Zadejte jméno prosím");
    this.setJmeno(jmeno);
    if(h==0||m==0||s==0)
        throw new IllegalArgumentException("Zadejte čas prosím");
    this.setCas(h, m, s);
}

public String getJmeno(){
    return jmeno;
}

public void setJmeno(String jmeno){
    this.jmeno = jmeno;
}

public void setCas(int h, int m, int s){
    this.hodina=h;
    this.minuta=m;
    this.sekunda=s;
}

public void getVysledek(){
    System.out.println(this.toString());
}

@Override
public int compareTo(Vysledek v){
    if(this.hodina<v.hodina && this.minuta<v.minuta && this.sekunda<v.sekunda)
        return -1;
    else if(this.hodina==v.hodina && this.minuta==v.minuta && this.sekunda==v.sekunda)
        return 0;
    else
        return 1;
}

@Override
public String toString(){
    return this.getJmeno()+", "+hodina+":"+minuta+"."+sekunda;
}
}

Then I have a class to create a list and store the results there.

public class SerazenySeznam<Vysledek extends Comparable<Vysledek>>{
    private java.util.List<Vysledek> vysledek = new java.util.ArrayList();
    
public void add(Vysledek v){
    if(v==null)
        throw new IllegalArgumentException("Vložte platný prvek");
    vysledek.add(v);
}

public void sort(){
    java.util.Collections.sort(vysledek);
    System.out.println(vysledek);
}

@Override
public String toString(){
    return vysledek.toString();
}
}

In the main class I have created a map, then I put the results inside the map and I wish to sort the results based on the time. As you can see, I created a method sort() in the class to create the least, but it does not sort anything.

public static void main(String[] args) {
        // TODO code application logic here
        java.util.Map<SerazenySeznam, Integer> mapa=new java.util.HashMap();
        
        SerazenySeznam<Vysledek> Monaco= new SerazenySeznam();
        
        Monaco.add(new Vysledek("Alain Prost",1,20,557));
        Monaco.add(new Vysledek("Michael Schmacher",1,21,190));
        Monaco.add(new Vysledek("Ayrton Senna",1,21,552));
        Monaco.add(new Vysledek("Érik Comas",1,23,246));
        Monaco.add(new Vysledek("Michael Andretti",1,22,994));
        Monaco.add(new Vysledek("Karl Wendlinger",1,22,477));
        Monaco.add(new Vysledek("Gerhard Berger",1,22,394));
        Monaco.add(new Vysledek("Riccardo Patrese",1,22,117));
        Monaco.add(new Vysledek("Jean Alesi",1,21,948));
        Monaco.add(new Vysledek("Damon Hill",1,21,825));
        
        Monaco.sort();
        
        mapa.put(Monaco, 1993);
        
        for(SerazenySeznam s : mapa.keySet())
            System.out.println(s);
    }

Could you tell me please how can I sort those results based on their time in the race? I hope I have been clear, but if there is something unclear, tell me and I can improve my question. Thanks in advance.

Upvotes: 1

Views: 108

Answers (3)

user2719475
user2719475

Reputation:

It is not a good idea to compare hours with hours, minutes with minutes and second with seconds to find which HH:MM:SS combination is the fastest. There can be cases like 04:50:56 < 05:00:00, which does not evaluate well in your original compareTo() method.

Try this code instead:

public int compareTo(Vysledek v){
    Integer counterSekundaThis = this.sekunda + this.minuta*60 +this.hodina*3600;
    Integer counterSekundaV = v.sekunda + v.minuta*60 + v.hodina*3600;

    return counterSekundaThis.compareTo(counterSekundaV);
}

Upvotes: 2

Yayotr&#243;n
Yayotr&#243;n

Reputation: 1889

I'd recommend that instead of storing it in your class

private int hodina;
private int minuta;
private int sekunda;

You use LocalTime for this purpose as it's Java's API to manage times. You can create an instance of it using LocalTime.of(hodina, minuta, sekunda). LocalTime already implements a compareTo to sort by time.

Your class could look something like this:

private static class Vysledek implements Comparable<Vysledek> {
    private String jmeno;
    private LocalTime time;

    public Vysledek(String jmeno, int h, int m, int s) {
      if (jmeno == null) {
        throw new IllegalArgumentException("Zadejte jméno prosím");
      }
      this.setJmeno(jmeno);
      time = LocalTime.of(h, m, s);
    }

    .
    .
    .
   
    @Override
    public int compareTo(Vysledek v) {
      return this.time.compareTo(v.time);
    }
  }

Upvotes: 2

Tess2552
Tess2552

Reputation: 86

Replace this in your Vysledek class

@Override
public int compareTo(Vysledek v){
    if(this.hodina<v.hodina && this.minuta<v.minuta && this.sekunda<v.sekunda)
        return -1;
    else if(this.hodina==v.hodina && this.minuta==v.minuta && this.sekunda==v.sekunda)
        return 0;
    else
        return 1;
}

with this

@Override
public int compareTo(Vysledek v) {
        return Integer.compare(this.sekunda + this.minuta*60000 + this.hodina*60000*60, v.sekunda + v.minuta*60000 + v.hodina*60000*60);
}

or you can even sort it in sort() method in your SerazenySeznam class without implementing Comparable in Vysledek class. But you need to make hodina, minuta, sekunda properties public or make getters.

public void sort(){
    vysledek.sort(new Comparator<Vysledek>() {
        @Override
        public int compare(Vysledek v1, Vysledek v2) {
            return Integer.compare(v1.sekunda + v1.minuta*60000 + v1.hodina*60000*60, v2.sekunda + v2.minuta*60000 + v2.hodina*60000*60);
        }
    });
}

PS: According to your test data, the sekunda property schould be named milisekunda, this answer treats it as milliseconds. If you want to treat it as seconds, replace previous with this:

Integer.compare(this.sekunda + this.minuta*60 + this.hodina*3600, v.sekunda + v.minuta*60+ v.hodina*3600);

Upvotes: 1

Related Questions