1

Basically, I'm trying to make a high-score display, comparing names and times (faster is better). I take the array of times, and sort them based on value (smallest to greatest). I then want the names to be re-arranged according to the times, which I am having trouble doing.

So basically, I want the input to be something like this:

John--8
Sally--5
James--2
Fred--4

And the output to be:

James--2
Fred--4
Sally--5
John--8

Currently, the output is:

John--2
Sally--4
James--5
Fred--8

Here is my code (note: you will need to have these text documents):

//not actually sure which of these import statements are really necessary, lol
import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.*;
import java.util.Vector;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Canvas;
import javax.swing.JFrame;
import java.awt.Dimension;
import java.io.*;

import java.util.Arrays;

class HallOfFame extends JFrame implements ActionListener 
{

    private static final int FRAME_WIDTH    = 300;
    private static final int FRAME_HEIGHT   = 350;

    int numberOfRows=20;

    String[] name = new String[100];
    String[] time = new String[100];

    //long[] longArrayTime = new long[100];

    String[] saneTime = new String[100];

    /*it's been a */long[] longTime = new long[100];

    long second;
    long minute;
    long hour;
    long miliseconds;
    //Declare your objects here...

    public static void main(String[] args) 
    {
        HallOfFame frame = new HallOfFame();  
        frame.setVisible(true); // Display the frame
    }

    @SuppressWarnings("unchecked")  //without this line, a warning appears. i can find no need for it and it's annoying, so i got rid of it :P (It is in relation to the table)
    public HallOfFame( ) 
    {  

        try 
        {
            File inFile= new File("names.txt");
            FileReader fileReader= new FileReader(inFile);
            BufferedReader bufReader = new BufferedReader(fileReader);

            for(int i=0; i<100; i++)
            {
                name[i]=bufReader.readLine();

            }
            bufReader.close();

        }
        catch(IOException tada)
        {
            JOptionPane.showMessageDialog(null, "Error loading high scores. Please ensure file system is accesible, and that 'name.txt' exists");
        }

        try 
        {
            File inFile= new File("times.txt");
            FileReader fileReader= new FileReader(inFile);
            BufferedReader bufReader = new BufferedReader(fileReader);

            for(int i=0; i<100; i++)
            {
                time[i]=bufReader.readLine();

            }
            bufReader.close();

        }
        catch(IOException tada)
        {
            JOptionPane.showMessageDialog(null, "Error loading high scores. Please ensure file system is accesible, and that 'name.txt' exists");
        }

        //finished reading scores
        for(int i=0;i<100;i++)
        {
            if(time[i]==null||time[i].equals(("0")))
            {
                time[i]="3699989"; //a very large value so that non-existant values are at the end of a sorted array
            }

            longTime[i] = Long.parseLong(time[i]);
        }
        Arrays.sort(longTime);


        for(int i=0;i<100;i++)
        {
            second = (longTime[i] / 1000) % 60;
            minute = (longTime[i] / (1000 * 60)) % 60;
            hour = (longTime[i] / (1000 * 60 * 60)) % 24;
            miliseconds = Long.parseLong((""+longTime[i]).substring(0,2));

            saneTime[i] = String.format("%02d:%02d:%d", minute, second, miliseconds);
        }

        // set the frame properties
        setTitle("High Scores");
        setSize(FRAME_WIDTH, FRAME_HEIGHT);
        setLocationRelativeTo(null);
        setResizable(false);
        Image icon = new ImageIcon("trophy.png").getImage();   //why does this not work????
        setIconImage(icon);

        Object columns[] = { "Rank", "Time", "Name" };
        DefaultTableModel model = new DefaultTableModel(columns, 0);

        for(int i=0;i<numberOfRows;i++)
        {
            if(time[i]=="3699989")//stop adding scores when array is empty (this large number is "empty" as 0 is defined to it above to make sorting the array work)
            {
                break;
            }
            Vector row = new Vector(numberOfRows);
            row.add((i+1));
            //row.add(time[i]);
            row.add(saneTime[i]);
            row.add(name[i]);
            model.addRow( row );
        }

        // set the content pane properties
        Container contentPane = getContentPane();   
        contentPane.setLayout(new GridLayout());
        contentPane.setBackground(Color.white);

        JTable table = new JTable( model );
        JScrollPane scrollPane = new JScrollPane(table);
        contentPane.add(scrollPane, BorderLayout.CENTER);

        for(int i=0;i<numberOfRows;i++)
        {
            table.setRowHeight(i, 30);
        }

        //create and place items frame's content pane

        // register 'Exit' upon closing as default close operation
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public void actionPerformed(ActionEvent event) // Actions
    {      
        JButton clickedButton = (JButton) event.getSource();        

    }   
} 
17
  • 4
    Basically, use the right data type for the job: 1) Create a class to capture name/time/etc; 2) Don't use a string to represent time - ideally use something from java.time, but possibly use an integer number of milliseconds or whatever. You can then easily sort the whole array or collection of items however you want. Commented Sep 12, 2016 at 7:45
  • 4
    Don't use parallel arrays/lists. Java is an Object-Oriented language. Use it! Create a class with your values, have a single array/list of objects of that class. Now you can sort to your hearts content, and values will always stay together. Commented Sep 12, 2016 at 7:45
  • 2
    @Blaine: So why are you storing that in an array? You can parse it as soon as you read it. You've presented too much code to be worth reading in detail, but I'm utterly convinced that sorting out your data model will make it much easier to achieve your goal. Commented Sep 12, 2016 at 7:49
  • 2
    @Blaine: If you don't know how to create your own class to capture the name/time/etc of a single game, I'd suggest concentrating on that instead of continuing GUI programming without knowing the basics of the language. Get hold of a good book and read it - and I'd suggest starting with console apps, as they're considerably simpler than GUIs, for learning the core parts of the language. Commented Sep 12, 2016 at 7:50
  • 2
    The logic behind what? How to create a class? How to create an array? How to sort an array? Follow advice by @JonSkeet: Get hold of a good book and read it. Commented Sep 12, 2016 at 8:15

3 Answers 3

2

Create a class which has the name and time as properties

public class Highscore {
    private String name;
    private long time;
    public Highscore(String name, long time) {
        this.name = name;
        this.time = time;
    }
    public String getName() {
        return this.name;
    }
    public long getTime() {
        return this.time;
    }
}

Then put all your Highscore objects into a collection. E.g.: ArrayList and sort those Objects using a Comparator.

Collections.sort(highscores, new Comparator<Highscore>() {
    @Override
    public int compare(Highscore hs1, Highscore hs2) {
        return Long.compare(hs1.getTime(), hs2.getTime());
    }
});

Or as suggested by @Andreas, if you're using Java 8 you can use the shortened expression to sort your ArrayList:

highscores.sort(Comparator.comparing(Highscore::getTime))
Sign up to request clarification or add additional context in comments.

4 Comments

Or highscores.sort(Comparator.comparing(Highscore::getTime)) in Java 8.
To compare two long values, use Long.compare(hs1.getTime(), hs2.getTime()). Of course, you'll need a getter method for any of this to work.
I suspect this solves the problem, but I honestly don't know how to use it
@Blaine It surely is okay not to understand something, but why don't you simply search it on the internet? The answer states "...sort those Objects using a Comparator". If you don't know what a Comparator is, then open a new tab, open a search engine, enter something like "java using comparator". And while your at a website like that, you can go on and read it's other articles, learning the coding style of java.
1

As many already mentioned you should realy try to use another data structure. I will try to keep your logic as it was and make some small improvements where needed.

//not actually sure which of these import statements are really necessary, lol
import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JTable;
import javax.swing.table.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

import javax.swing.JFrame;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Vector;
import java.util.concurrent.TimeUnit;

class HallOfFame extends JFrame implements ActionListener 
{

    private static final int FRAME_WIDTH    = 300;
    private static final int FRAME_HEIGHT   = 350;

    int numberOfRows=20;

    String[] name = new String[100];
    String[] time = new String[100];

    //long[] longArrayTime = new long[100];

    String[] saneTime = new String[100];

    /*it's been a */long[] longTime = new long[100];

    long second;
    long minute;
    long hour;
    long miliseconds;
     //Declare your objects here...

     public static void main(String[] args) 
     {
         HallOfFame frame = new HallOfFame();  
         frame.setVisible(true); // Display the frame
      }

    @SuppressWarnings("unchecked")  //without this line, a warning appears. i can find no need for it and it's annoying, so i got rid of it :P (It is in relation to the table)
    public HallOfFame( ) 
    {  

        try 
        {
            File inFile= new File("names.txt");
            FileReader fileReader= new FileReader(inFile);
            BufferedReader bufReader = new BufferedReader(fileReader);

            for(int i=0; i<100; i++)
            {
                 name[i]=bufReader.readLine();

            }
            bufReader.close();

            }
            catch(IOException tada)
            {
            JOptionPane.showMessageDialog(null, "Error loading high scores. Please ensure file system is accesible, and that 'name.txt' exists");
          }

          try 
          {
           File inFile= new File("times.txt");
           FileReader fileReader= new FileReader(inFile);
           BufferedReader bufReader = new BufferedReader(fileReader);

           for(int i=0; i<100; i++)
           {
            time[i]=bufReader.readLine();

        }
        bufReader.close();

    }
    catch(IOException tada)
    {
        JOptionPane.showMessageDialog(null, "Error loading high scores. Please ensure file system is accesible, and that 'name.txt' exists");
    }

    //finished reading scores
    for(int i=0;i<100;i++)
    {
        if(time[i]==null||time[i].equals(("0")))
        {
            time[i]="3699989"; //a very large value so that non-existant values are at the end of a sorted array
        }

        longTime[i] = Long.parseLong(time[i]);
    }
    //Arrays.sort(longTime); removed

    /* removed and replaced with a method which returns HH:mm:ss for given milliseconds
    for(int i=0;i<100;i++)
    {
        second = (longTime[i] / 1000) % 60;
        minute = (longTime[i] / (1000 * 60)) % 60;
        hour = (longTime[i] / (1000 * 60 * 60)) % 24;
        miliseconds = Long.parseLong((""+longTime[i]).substring(0,2));

        saneTime[i] = String.format("%02d:%02d:%d", minute, second, miliseconds);
    }*/

    class Player implements Comparable<Player>{     //added a class player with the atr. name and time
        String name;
        Long time;

        Player(String name, Long time){
            this.name = name;
            this.time = time;
        }
        @Override
        public int compareTo(Player p) {        // a compareTo method which is needed to sort a list of players
          return time.compareTo(p.time);        // sorting by time, you can change this to sort by name age or sth.else
        }
    }

    ArrayList<Player> playerslist = new ArrayList<>(); // an ArrayList to hold your data  
    for(int i=0;i<100;i++){
        Player p = new Player(name[i],longTime[i]);
        playerslist.add(p);
    }
    Collections.sort(playerslist);

    // set the frame properties
    setTitle("High Scores");
    setSize(FRAME_WIDTH, FRAME_HEIGHT);
    setLocationRelativeTo(null);
    setResizable(false);
    Image icon = new ImageIcon("trophy.png").getImage();   //why does this not work????
    setIconImage(icon);

    Object columns[] = { "Rank", "Time", "Name" };
    DefaultTableModel model = new DefaultTableModel(columns, 0);

       for(int i=0;i<numberOfRows;i++)
       {
           if(playerslist.get(i).time >1000000)//stop adding scores when array is empty (this large number is "empty" as 0 is defined to it above to make sorting the array work)
          {
            break;
           }
          Vector row = new Vector(numberOfRows);
          row.add((i+1));
          //row.add(time[i]);
          row.add(convertSecondsToHMmSs(playerslist.get(i).time));
          row.add(playerslist.get(i).name);
          model.addRow( row );
       }

    // set the content pane properties
    Container contentPane = getContentPane();   
    contentPane.setLayout(new GridLayout());
    contentPane.setBackground(Color.white);

    JTable table = new JTable( model );
    JScrollPane scrollPane = new JScrollPane(table);
    contentPane.add(scrollPane, BorderLayout.CENTER);

    for(int i=0;i<numberOfRows;i++)
    {
        table.setRowHeight(i, 30);
    }

    //create and place items frame's content pane

    // register 'Exit' upon closing as default close operation
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public void actionPerformed(ActionEvent event) // Actions
    {      
      JButton clickedButton = (JButton) event.getSource();        

    }

     public static String convertSecondsToHMmSs(long millis) {       // method to change milliseconds to HH:mm:ss
    return String.format("%02d:%02d:%02d", 
    TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) -  
    TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), 
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
     TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))); 
  }
}

1 Comment

Thank you!! This was the example I was looking for. The one that showed how to actually use it in the overall program
-2

A simple solution, which isn't optimzed, would be to rearrange your array (swap name and value positions) and then sort it (Arrays,sort)

    public class SortArray {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String [] arr = new String[4];

        arr[0] = "John--8";
        arr[1] = "Sally--5";
        arr[2] = "James--2";
        arr[3] = "Fred--4";
        sortArr(arr);
        for(int i = 0; i < arr.length; ++i){
            String []  splitArr = arr[i].split("--");
            System.out.println(splitArr[1] +"--"+splitArr[0]);
        }
    }
    public static void sortArr(String [] arr) {

        int len = arr.length;

        for(int i = 0; i < len; ++i) {
            String []  splitArr = arr[i].split("--");

            arr[i] = splitArr[1] +"--" +splitArr[0];

        }

        Arrays.sort(arr);


    }

}

The output is

James--2
Fred--4
Sally--5
John--8

7 Comments

This is a bad solution to the problem, IMO. Using proper object orientation is far superior to shoving everything into a string.
actually, at the moment, I perfer a less proper solution that I actually understand with my limited knowlage
still, the issue with this is that both values are in the same variable
@Blaine: I would strongly advise you not to just keep going without learning the basics of the language. Take a bit of time on each step and you'll avoid getting yourself into deep water too quickly.
@Blaine Don't go with a hack solution like this, since it will sort the time values as strings, e.g. 10 sorts before 9, so it won't work right.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.