【问题标题】:How to sort a continuously updated (dynamic) object in an array如何对数组中不断更新的(动态)对象进行排序
【发布时间】:2020-08-07 15:54:49
【问题描述】:

我正在构建一个经典的 Nim 游戏。到目前为止,我已经完成了玩家部分和游戏部分。现在,我正在尝试对数组中的对象进行排序(排名)。我为排序构建了以下内容:

  1. playerList
  2. winRatio,在 NimPlayer 类及其 getter 中设置。

目标:

  1. winRatio 进行降序排序,即从最高分到最低分。该比率由score/gamePlayed 计算得出。
  2. 如果出现平局,请使用userName 按字母顺序排序。

我已经提到过这个问题:How to sort an array of objects in Java?

我知道我应该做的是使用ComparableComparator 进行排序,但从文章中,他们使用对象中的属性进行排序(到目前为止我找到的所有信息)。我正在处理的是构造函数之外不断更新的数据。

我试过的是不排序直接打印出来的数据。

这是我的相关代码(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) ;
}
}

这是我的主要课程 (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(); 
            }            
        }
        }

非常感谢任何帮助。

【问题讨论】:

  • 你应该先看看 java 集合框架,如果你不必自己实现的话,已经有很多符合你期望的数据结构实现了。
  • 感谢您的推荐。我试图在不使用ArrayList 的情况下处理它。当然,ArrayList 可以节省很多时间和精力。

标签: java arrays sorting


【解决方案1】:

使用Interface Comparator

按如下方式进行:

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();
    }
}

输出:

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

注意:如果您希望在searchAndPrintRankingData 中使用ArrayList&lt;NimPlayer&gt;,下面给出的是相同的代码:

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);
}

【讨论】:

  • 非常感谢,先生!我认为使用ArrayList 将是最后一种方式,对吧?仅使用数组会引发NullPointerException 是否有null? @Arvind
  • 不客气。我已经更新了使用NimPlayer[] 而不是List&lt;NimPlayer&gt; 的答案。我还在末尾添加了我对该方法的原始定义searchAndPrintRankingData 作为Note
  • 非常感谢,先生。它运行良好,您的代码非常清晰易读。我现在正在处理打印格式。大概我明天就完成了。祝你今天过得愉快。 @Arvind
【解决方案2】:

你的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;
    }
}

另外,你需要修复你的 playerList 的大小,设置为 2 static NimPlayer[] playerList = new NimPlayer[2];,然后你尝试添加最多 10 个玩家:)

在将玩家添加到列表时,您最好将counter 与实际的playerList.length; 进行比较

【讨论】:

  • 感谢您指出问题。我从没想过计数器和 playerList 的长度。在这个问题中,排序创建getPlayerList()后,是不是一定要返回?而且,我应该如何将这两种方法称为Nimsys? @亚历克斯
  • 抱歉,我没有注意到排序后的数组没有返回 - 修复了该问题并更新了列表的 getter 名称。因此,您的 Nimsys 代码可以保持不变 - 方法 compareToArrays.sort 的内部调用,当您调用 getPlayer 时,您将获得排序数组
【解决方案3】:

它应该通过实现Comparable 接口来工作,因为每次您想要排序时都会调用compareTo 方法,并且会获得更新的数据。

先按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);
    }

}

然后,要对数组进行排序,您只需要使用Arrays 类:

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

您可能面临的问题是,如果您总是希望用户名按 ASC 排序。 在这种情况下,您唯一的选择是实现两个不同的比较器,一个用于升序,另一个用于降序:

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());
};

要使用这些比较器进行排序,只需将比较器传递给Arrays.sort 方法:

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

【讨论】:

  • 我在写Comparator&lt;NimPlayer&gt; 部分时卡住了。我把它放到NimPlayer 类中。我只能将一个论点放在括号内。再次感谢您的耐心和时间来解决这个问题。
  • 您使用的是哪个 java 版本?如果使用 = 8,请使用您的新代码更新问题,以及引发错误的确切点
  • 我在 Windows 上检查了我的 java 版本。它应该是版本 8。我在想,如果我的 VsCode 出现问题。
  • docs.oracle.com/javase/8/docs/api/java/util/Comparator.html 这是我没有看到类似您的代码的文档。我错过了什么吗?
  • 我正在使用 Java 8 lambdas 创建比较器。您可以在此链接中查看有关该内容的好文章:baeldung.com/java-8-sort-lambda
【解决方案4】:

对于升序排序,请使用您提到的代码链接。只要玩家已经添加到数组中,就可以对其进行排序。下面的代码是关键(您需要调整变量名称等) 您需要将 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));
}

改变这个:

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

收件人:

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

【讨论】:

  • 其实我几个小时前就尝试过这个方法,但是请原谅我不知道如何在不使用toString()的情况下传递函数。我想在Nimsys 中打印出结果,这是我的主要方法。因此,我很想知道如何处理这个问题。
  • 如果排序书功能是从 NimPlayer 类调用的,您可以在从该类调用时创建一个 ToString。无需赘述,这应该可以使用 oop 原则
猜你喜欢
  • 2021-06-05
  • 2015-09-15
  • 2018-10-11
  • 2013-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
相关资源
最近更新 更多