简体   繁体   English

如何对数组中的连续更新(动态)object 进行排序

[英]How to sort a continuously updated (dynamic) object in an array

I am building a classical Nim game.我正在构建一个经典的 Nim 游戏。 So far, I've done the player part and the game part.到目前为止,我已经完成了玩家部分和游戏部分。 Now, I am trying to sort(rank) the object in an array.现在,我正在尝试对数组中的 object 进行排序(排序)。 I've built the following for sorting:我为排序构建了以下内容:

  1. playerList
  2. winRatio , which is set in the NimPlayer class with its getter. winRatio ,它在NimPlayer class 中使用它的 getter 设置。

The aim:目的:

  1. to sort the winRatio descendingly, which means from the highest score to the lowest one.winRatio降序排序,即从最高分到最低分。 The ratio is calculated by score/gamePlayed .该比率由score/gamePlayed计算。
  2. If there's a tie, sort using userName alphabetically.如果有平局,则使用userName按字母顺序排序。

I've referred to this issue: How to sort an array of objects in Java?我提到过这个问题: How to sort an array of objects in Java?

I know what I should do is use the Comparable or Comparator for sorting but from the article, they sort using the attributes in the object (All the information I've found so far).我知道我应该做的是使用ComparableComparator进行排序,但从文章中,他们使用 object 中的属性进行排序(到目前为止我找到的所有信息)。 What I am dealing with is the continuously updated data outside the constructor.我处理的是构造函数之外不断更新的数据。

What I've tried was directly printed out the data without sorting.我试过的是不排序直接打印出数据。

Here is my related code ( NimPlayer ):这是我的相关代码( NimPlayer ):

public class NimPlayer {
private String userName;
private String familyName;
private String givenName;

static int counter;
private int score;
private int gamePlayed;
static NimPlayer[] playerList = new NimPlayer[2]; // set an array here

//define NimPlayer data type
public NimPlayer(String userName, String surName, String givenName) {
    this.userName = userName;
    this.familyName = surName;
    this.givenName = givenName;

}
// create new data using NimPlayer data type
public static void createPlayer(String userName, String familyName, String givenName) {
    if (counter<10) {
        playerList[counter++] = new NimPlayer(userName, familyName, givenName);
    } else {
        System.out.println("Cannot add more players.");
    }

// all the getter and setter related to the constructor; the getter of the player list.

}
public void setScore(int score) {
    this.score=score;
}
public int getScore() {
    return score;
}
public void setGamePlayed (int gamePlayed) {
    this.gamePlayed = gamePlayed;
}
public int getGamePlayed() {
    return gamePlayed;
}
public int getWinRatio () {
    return Math.round(Float.valueOf(getScore())/ (getGamePlayed()+1)*100) ;
}
}

This is my main class ( Nimsys )这是我的主 class ( Nimsys )

public static void searchAndPrintRankingData() {
    for (int i = 0; i < NimPlayer.getCounter(); i++) {

        String familyName = NimPlayer.getPlayer()[i].getFamilyName();
        String givenName = NimPlayer.getPlayer()[i].getGivenName();
        int score = NimPlayer.getPlayer()[i].getScore();
        int gamePlayed = NimPlayer.getPlayer()[i].getGamePlayed();
        double winRatio = score/(gamePlayed+1);//wrong calculation for testing

        System.out.println(winRatio+"% | "+gamePlayed+" games | "+givenName+" "+familyName);
    }
}

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    while (true) {
        System.out.print('$');
        String commandin = in.next();
if (commandin.equals("rankings")) {
            String commandOrder = in.nextLine().trim();

            if (commandOrder.equals("asc")) {
                //sort the data
                searchAndPrintRankingData();
            }

            if (commandOrder.equals("") || commandOrder.equals("desc")) {
                //sort the data

                searchAndPrintRankingData(); 
            }            
        }
        }

Any help is highly appreciated.非常感谢任何帮助。

Use Interface Comparator使用接口比较器

Do it as follows:做如下:

import java.util.Arrays;
import java.util.Comparator;

class NimPlayer {
    private String userName;
    private String familyName;
    private String givenName;

    private static int counter;
    private static final int SIZE = 4;
    private int score;
    private int gamePlayed;

    static NimPlayer[] playerList = new NimPlayer[SIZE];

    public NimPlayer(String userName, String surName, String givenName) {
        this.userName = userName;
        this.familyName = surName;
        this.givenName = givenName;
    }

    public static void createPlayer(String userName, String familyName, String givenName) {
        if (counter < SIZE) {
            playerList[counter++] = new NimPlayer(userName, familyName, givenName);
        } else {
            System.out.println("Cannot add more players.");
        }
    }

    public static int getCounter() {
        return counter;
    }

    public static NimPlayer[] getPlayerList() {
        return playerList;
    }

    public String getUserName() {
        return userName;
    }

    public String getFamilyName() {
        return familyName;
    }

    public String getGivenName() {
        return givenName;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public int getScore() {
        return score;
    }

    public void setGamePlayed(int gamePlayed) {
        this.gamePlayed = gamePlayed;
    }

    public int getGamePlayed() {
        return gamePlayed;
    }

    public int getWinRatio() {
        return Math.round((Float.valueOf(score) / gamePlayed) * 100);
    }

    @Override
    public String toString() {
        return "User Name: " + userName + ", Name: " + givenName + " " + familyName + ", Score: " + score
                + ", Games Played: " + gamePlayed + ", Win ratio: " + getWinRatio();
    }

}

public class Main {
    static void searchAndPrintRankingData() {
        NimPlayer[] players = NimPlayer.getPlayerList();
        Arrays.sort(players,
                Comparator.comparing((NimPlayer::getWinRatio)).reversed().thenComparing(NimPlayer::getUserName));

        Arrays.stream(players).forEach(System.out::println);
    }

    public static void main(String[] args) {
        NimPlayer.createPlayer("Avi", "Avinash", "Arvind");
        NimPlayer.createPlayer("Harry", "Potter", "Harry");
        NimPlayer.createPlayer("Vishy", "Anand", "Vishwanathan");
        NimPlayer.createPlayer("Bond", "Bond", "James");

        NimPlayer[] players = NimPlayer.getPlayerList();

        players[0].setGamePlayed(2);
        players[0].setScore(40);

        players[1].setGamePlayed(3);
        players[1].setScore(75);

        players[2].setGamePlayed(2);
        players[2].setScore(120);

        players[3].setGamePlayed(4);
        players[3].setScore(100);

        System.out.println("Unsorted: ");
        Arrays.stream(NimPlayer.getPlayerList()).forEach(System.out::println);

        System.out.println();

        System.out.println("Sorted on win ratio (then name, in case of tie): ");
        searchAndPrintRankingData();
    }
}

Output: Output:

Unsorted: 
User Name: Avi, Name: Arvind Avinash, Score: 40, Games Played: 2, Win ratio: 2000
User Name: Harry, Name: Harry Potter, Score: 75, Games Played: 3, Win ratio: 2500
User Name: Vishy, Name: Vishwanathan Anand, Score: 120, Games Played: 2, Win ratio: 6000
User Name: Bond, Name: James Bond, Score: 100, Games Played: 4, Win ratio: 2500

Sorted on win ratio (then name, in case of tie): 
User Name: Vishy, Name: Vishwanathan Anand, Score: 120, Games Played: 2, Win ratio: 6000
User Name: Bond, Name: James Bond, Score: 100, Games Played: 4, Win ratio: 2500
User Name: Harry, Name: Harry Potter, Score: 75, Games Played: 3, Win ratio: 2500
User Name: Avi, Name: Arvind Avinash, Score: 40, Games Played: 2, Win ratio: 2000

Note: In case you wish to use ArrayList<NimPlayer> in searchAndPrintRankingData , given below is the code for the same:注意:如果您希望在searchAndPrintRankingData中使用ArrayList<NimPlayer> ,下面给出的是相同的代码:

static void searchAndPrintRankingData() {
    List<NimPlayer> players = new ArrayList<NimPlayer>(Arrays.asList(NimPlayer.getPlayerList()));
    Collections.sort(players,
            Comparator.comparing((NimPlayer::getWinRatio)).reversed().thenComparing(NimPlayer::getUserName));

    players.stream().forEach(System.out::println);
}

For sort ascending use the code link you mentioned.对于升序排序,请使用您提到的代码链接。 As long as the players have been added to the array, you can sort them.只要玩家已经添加到数组中,就可以对他们进行排序。 The code below is the key (you will need to adapt variable names etc) You will need to add winRation etc to NimPlayer constructor and as element of the array, then it can sort it.下面的代码是关键(你需要调整变量名等)你需要将 winRation 等添加到 NimPlayer 构造函数中并作为数组的元素,然后它可以对其进行排序。

@Test
public void sortBooks() {
Book[] books = {
        new Book("foo", "1", "author1", "pub1"),
        new Book("bar", "2", "author2", "pub2")
};

// 1. sort using Comparable
Arrays.sort(books);
System.out.println(Arrays.asList(books));

// 2. sort using comparator: sort by id
Arrays.sort(books, new Comparator<Book>() {
    @Override
    public int compare(Book o1, Book o2) {
        return o1.id.compareTo(o2.id);
    }
});
System.out.println(Arrays.asList(books));
}

Change this:改变这个:

 return o1.id.compareTo(o2.id);

To:到:

return o1.winRatio.compareTo(o2.winRatio);

It should work by implementing the Comparable interface, as the compareTo method will be called each time you want to sort and will have the updated data.它应该通过实现Comparable接口来工作,因为每次您要排序时都会调用compareTo方法并将更新数据。

To sort first by winRatio , and if equal, by name , it can work with the following code:要首先按winRatio排序,如果相等,则按name排序,它可以使用以下代码:

public class NimPlayer implements Comparable<NimPlayer> {

    ...

    @Override
    public int compareTo(NimPlayer o) {
        // get the comparison of the win ratios
        int ratioCompare = this.getWinRatio().compareTo(o.getWinRatio());
        // if the winRatio is equal, return the reverse comparison of the usernames
        return (ratioCompare != 0) ? ratioCompare : o.userName.compareTo(this.userName);
    }

}

Then, to sort the array, you just need to use the Arrays class:然后,要对数组进行排序,您只需要使用Arrays class:

Arrays.sort(NimPlayer.playerList);
Arrays.sort(NimPlayer.playerList, Collections.reverseOrder()); // for desc order

The problem you may face with that is if you always want to have the username ordered ASC.您可能面临的问题是,如果您总是希望用户名按 ASC 顺序排列。 In that case, your only option is to implement two different comparators, one for ascending and another for descending orders:在这种情况下,您唯一的选择是实现两个不同的比较器,一个用于升序,另一个用于降序:

Comparator<NimPlayer> ascComparator = (p1, p2) -> {
    int ratioCompare = p1.getWinRatio().compareTo(p2.getWinRatio());
    return (ratioCompare != 0) ? ratioCompare : p1.getUserName().compareTo(p2.getUserName());
};

Comparator<NimPlayer> descComparator = (p1, p2) -> {
    int ratioCompare = p2.getWinRatio().compareTo(p1.getWinRatio());
    return (ratioCompare != 0) ? ratioCompare : p1.getUserName().compareTo(p2.getUserName());
};

To sort using those comparators, just pass the comparators into the Arrays.sort method:要使用这些比较器进行排序,只需将比较器传递给Arrays.sort方法:

Arrays.sort(NimPlayer.playerList, ascComparator);
Arrays.sort(NimPlayer.playerList, descComparator);

Your NimPlayer needs to implement Comparable interface:你的NimPlayer需要实现Comparable接口:

public class NimPlayer implements Comparable<NimPlayer> {

    @Override
    public int compareTo(NimPlayer other) {
        if (other.getWinRatio() == this.getWinRatio()) {
            return this.getUserName().compareTo(other.getUserName());
        } else if (other.getWinRatio() > this.getWinRatio()) {
            return 1;
        }
        return -1;
    }

    public static NimPlayer[] getPlayer() {
        Arrays.sort(playerList);
        return playerList;
    }
}

Also, you need to fix the size of your playerList, which is set to 2 static NimPlayer[] playerList = new NimPlayer[2];此外,您需要修复播放器列表的大小,设置为 2 static NimPlayer[] playerList = new NimPlayer[2]; , and then you try to add up to 10 players:) , 然后你尝试添加最多 10 个玩家:)

And when adding players to the list you'd better compared counter to actual playerList.length;并且在将玩家添加到列表中时,最好将counter与实际playerList.length;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM