给出错误结果的子列表的 Java 反向顺序

A. *_*ijk 2 java sorting collections arraylist

我有问题。我将代码简化为一个小型演示程序。有 1 个类命名Visitor,它看起来像这样:

public class Visitor implements Comparable<Visitor> {

    private Integer id;
    private String name;
    private static int lastIdGiven = 0;

    public Visitor(Integer id) {
        this.id = id;
    }

    public Visitor(String name) {
        this.id = getNewId();
        this.name = name;
    }

    private int getNewId() {
        this.lastIdGiven++;
        return this.lastIdGiven;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public int compareTo(Visitor o) {
        return this.id.compareTo(o.id);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我创建一个List<Visitor>并添加 20 个访问者作为我的示例。我想要的是遍历列表并根据 Id 获取当前访问者下方的 5 个访问者。这是代码:

public class Main {

    public static final int NUM_OF_VISITORS_IN_LIST = 5;

    public static void main(String[] args) {

        ArrayList<Visitor> visitorList = new ArrayList<>();

        for (Integer i = 0; i < 20; i++) {
            Visitor visitor = new Visitor("visitor " + i.toString());
            visitorList.add(visitor);
        }

        visitorList.sort(Visitor::compareTo);

        for(Visitor visitor : visitorList) {

            int visitorSearchId = visitor.getId();
            Visitor searchVisitor = new Visitor(visitorSearchId);

            int endIndex = Collections.binarySearch(visitorList, searchVisitor);
            int startIndex = endIndex - NUM_OF_VISITORS_IN_LIST;

            if (startIndex >= 0) {
                List<Visitor> foundVisitors = visitorList.subList(startIndex, endIndex);

                // REVERSE THE SORTING
                //foundVisitors.sort(Visitor::compareTo);
                //foundVisitors.sort(Collections.reverseOrder());
                System.out.println("For visitor-Id: " + visitor.getId() + ", are the following visitors found:");
                for (Visitor foundVisitor : foundVisitors) {
                    System.out.println("\tId: " + foundVisitor.getId());
                }
                System.out.println();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一张访客打印:

For visitor-Id: 19, are the following visitors found:
    Id: 14
    Id: 15
    Id: 16
    Id: 17
    Id: 18
Run Code Online (Sandbox Code Playgroud)

但现在我想对 5 个 foundVisitor 进行反向排序。为此,我将代码注释掉了,但我有以下几行:

foundVisitors.sort(Visitor::compareTo);
foundVisitors.sort(Collections.reverseOrder());
Run Code Online (Sandbox Code Playgroud)

然而,这给我带来了一个非常奇怪的列表,它从原始列表中获取旧数据:

For visitor-Id: 19, are the following visitors found:
    Id: 18
    Id: 4
    Id: 3
    Id: 2
    Id: 1
Run Code Online (Sandbox Code Playgroud)

我以为我会得到以下输出:

For visitor-Id: 19, are the following visitors found:
        Id: 18
        Id: 17
        Id: 16
        Id: 15
        Id: 14
Run Code Online (Sandbox Code Playgroud)

此处放弃的代码是我的整个项目,因此如果您愿意,您都可以复制它:) 出了
什么问题,我该如何解决?

dre*_*ash 5

要解决您的问题,您只需执行以下操作,替换:

List<Visitor> foundVisitors = visitorList.subList(startIndex, endIndex);
foundVisitors.sort(Collections.reverseOrder());
           
Run Code Online (Sandbox Code Playgroud)

为了:

  List<Visitor> sublist = visitorList.subList(startIndex, endIndex);
  List<Visitor> foundVisitors = new ArrayList<>(sublist);
  foundVisitors.sort(Collections.reverseOrder());
Run Code Online (Sandbox Code Playgroud)

subList方法不会返回一个新的list,而是一个原始列表的视图。正如人们可以在这里阅读的那样:

subList(int fromIndex, int toIndex)返回此列表中指定的 fromIndex(包含)和 toIndex(不包含)之间的部分的视图。

因此,当你做

foundVisitors.sort(Collections.reverseOrder());

你已经弄乱了原始列表的顺序。因此,您有理由首先需要做

 List<Visitor> foundVisitors = new ArrayList<>(sublist);
Run Code Online (Sandbox Code Playgroud)

旁注:

    for (Integer i = 0; i < 20; i++) {
        Visitor visitor = new Visitor("visitor " + i.toString());
        visitorList.add(visitor);
    }
Run Code Online (Sandbox Code Playgroud)

可以简化为:

    for (int i = 0; i < 20; i++) {
        Visitor visitor = new Visitor("visitor " + i);
        visitorList.add(visitor);
    }
Run Code Online (Sandbox Code Playgroud)

更新:

与您问题的主要问题无关,但仍然是值得一提的优化。霍格推荐:

使用基于索引的循环将消除对您已经知道位置的元素进行二分搜索的需要。实际上,您可以从该索引向后循环并打印五个元素,那么您既不需要子列表也不需要反向排序。

所以你的代码可以简化为:

public static void main(String[] args) {

    ArrayList<Visitor> visitorList = new ArrayList<>();

    for (int i = 0; i < 20; i++) {
        Visitor visitor = new Visitor("visitor " + i);
        visitorList.add(visitor);
    }
    visitorList.sort(Visitor::compareTo);
    for(int i = NUM_OF_VISITORS_IN_LIST; i < visitorList.size(); i++) {
        System.out.println("For visitor: " + visitorList.get(i));
        for(int j = i, end = i - NUM_OF_VISITORS_IN_LIST; j > end;) {
            System.out.println(visitorList.get(--j).getId());
        }
        System.out.println();
    }
}
Run Code Online (Sandbox Code Playgroud)