【问题标题】:Sorting a list based on another list's values - Java根据另一个列表的值对列表进行排序 - Java
【发布时间】:2011-01-29 22:44:51
【问题描述】:

一个带有名字的列表:(未排序)例如[paul,follow,mark]

另一个整数列表:例如 [5, 2, 6]

第二个列表中的值是每个人(姓名)“选择”的数字,所以 保罗5号,犯规2号,马克6号。

我正在尝试根据第二个列表的值按降序对姓名列表进行排序。我不能使用地图,因为我在程序的其他场合需要这两个列表。

使用排序方法我做了我得到这样的列表:[paul, mark, fur]

如您所见,它没有按我想要的方式排序。

正确的应该是:[mark,paul,foul]

但我找不到代码的错误。

public ArrayList<String> sortNames(ArrayList<Integer> results){
    String tmp;
    for (int k=0; k<Names.size()-1; k++) {

        boolean isSorted=true;
        for (int i=1; i<Names.size()-k; i++) {

             if (results.get(i)>results.get(i-1)  ) {

                tmp=Names.get(i);
                Names.set(i,Names.get(i-1));
                Names.set(i-1,tmp);

                isSorted=false;
            }
        }
        if (isSorted) break;
    }
    return Names;

}

编辑!!!在下面的答案的帮助下,代码是:

    public ArrayList<String> sortNames(ArrayList<Integer> results){
        String tmp2;
        int tmp;
        for (int k=0; k<Names.size()-1; k++) {

            boolean isSorted=true;
            for (int i=1; i<Names.size()-k; i++) {

                 if (results.get(i)>results.get(i-1)  ) {
                     tmp=results.get(i);
                     results.set(i,results.get(i-1));
                     results.set(i-1,tmp);


                    tmp2=Names.get(i);
                    Names.set(i,Names.get(i-1));
                    Names.set(i-1,tmp2);

                    isSorted=false;
                }
            }
            if (isSorted) break;
        }
    return Names;

}

此代码正常工作(对于小列表) 我只是询问为什么它不适用于 ImageIcon 之类的对象。有什么想法吗?

【问题讨论】:

  • “我不能使用地图,因为在我的程序的其他场合我需要这两个列表。”究竟要做什么?
  • 例如,其他类需要列表。是否可以在地图上对它们进行排序,然后单独使用它们? ://
  • 写下你在网上找到的任何排序算法 quick/merge/shell/whatever 并且当你交换时,交换两个列表
  • 致任何提供 Map 用途的人:它不允许 duplicates
  • 我知道它不能,但多图(例如来自 Guava)可能会完成这项工作。

标签: java sorting


【解决方案1】:

摆脱这两个列表。如果数据是相关的,那么数据应该一起存储在一个简单的类中。然后将整个类添加到列表中,如果需要,您可以在其中对各个属性进行排序。您可以使用Bean Comparator 对这个列表进行任何您想要的排序。

【讨论】:

  • ^this 应该是公认的答案,即使它没有直接回答问题。我打算将 int+string 的包装放入一个可比较的类中并对其进行排序,然后将其解包,但这只是数据结构存在缺陷。当使用 2/3/n 单独的数组在 java 中是一种很好的做法(但在 c 中不是)时,有一种特殊情况。它使用非常简单但异常众多的结构(例如复数)工作;拥有 2 个数组 double[] a,b 比 Complex{double a,b} 类的数组在性能(和内存)方面要好得多。然而,只有在这种情况下。
【解决方案2】:

您正在根据列表结果的值对列表名称进行排序......并且它仅由于条件k&lt;Names.size()-1 而终止。这样的条件在冒泡排序中通常是不需要的,这就说明有问题了。

您必须交换两个列表中的元素,而不仅仅是名称。这就是答案,但请注意冒泡排序是有史以来最糟糕的算法之一。

编辑:

我不能使用地图,因为我在程序的其他场合需要这两个列表。

当然可以(假设数字是唯一的):

Map<Integer, String> m = new HashMap<Integer, String>();
for (int i=0; i<results.size(); ++i) m.put(results.get(i), Names.get(i));
Collections.sort(results);
for (int i=0; i<results.size(); ++i) Names.set(i, m.get(results.get(i));

可能有错误,但思路要清楚。

还有另一种解决方案,使用一类对(结果、名称),如果您需要,它甚至可以处理非唯一数字。

稍微短一点的解决方案:

Map<Integer, String> m = new TreeMap<Integer, String>();
for (int i=0; i<results.size(); ++i) m.put(results.get(i), Names.get(i));
Names.clear();
Names.addAll(m.values());

这是基于TreeSet.values集合的迭代器按相应键的升序返回值”和List.addAll附加指定的所有元素的属性集合到此列表的末尾,按照指定集合的​​迭代器返回的顺序"

【讨论】:

  • 你说的交换是正确的!谢谢!你能解释一下你一开始是什么意思吗?我知道bubblesort在大小的计数器上不需要-1。但是仅测试您发布的第二个注释我得到了正确的结果。第一个怎么没有反应? :/ 编辑:在您编辑之前发布的评论。
  • 通常,冒泡排序会因为外循环中断而终止。众所周知,它不能超过 N-1 次迭代,但您不需要这样的条件 s。 en.wikipedia.org/wiki/Bubble_sort#Pseudocode_implementation 你的错误实现永远不会终止(除非以排序序列开始)。但这并不重要……这只是我看到的第一个想法。
  • Collections.sort() 需要 List,而 HashMap 没有实现。
  • Using map, is it possible after to use separately the 2 lists? - 当然,地图只是临时的。 As for the bubblesort - 如果您的列表保证非常短(
  • Collections.sort() requires a List, which HashMap doesn't implement. - 我用sort(map)是个傻瓜吗?
【解决方案3】:
  1. 通过成对地从两个列表中获取元素(具有将两个值存储为字段的类)来构建(名称,值)对的列表。实现 Comparable 来比较 value 字段。

  2. 使用Collections.sort()对结果进行排序。

  3. 从排序列表中提取名称。

【讨论】:

  • 感谢 Karl Knechtel。你的提议是对的。我仍然在想,如果不是使用另一个类,最好让它像我发布的那样,并且只使用@maaartinus 所说的关于对第二个列表进行排序的内容。
  • 如您所见,使用自制算法非常容易出错。而 buublesort 对于更长的列表来说简直是太糟糕了。顺便说一句,我在第一次编辑结束时提到了卡尔的方法,只是写了很多。
  • 啊哈谢谢 maaartinus。至于气泡排序,请记住,我的列表最大大小为 4。所以我不认为气泡效果太大,这就是我选择它的原因。感谢您的想法。
  • @maaartinus 如果不能实现排序算法,那就没什么意义了
【解决方案4】:

你可以使用你所得到的最普通的快速排序,最简单的原则是:当你交换第一个列表时,你去交换第二个。希望这不是家庭作业,但即使不是…… 简而言之,复制/粘贴并享受quickSort(list1, list2) 就是您所需要的。列表按Comparable 定义的第一个列表自然顺序排序。

private static void swap(List<?> l1, List<?> l2, int i, int j){
    Collections.swap(l1, i, j);
    Collections.swap(l2, i, j);     
}
private static <T extends Comparable<? super T>>  int partition(List<T> comp, List<?> l2, int left, int right){
    int i = left, j = right;
    T pivot = comp.get((left + right) / 2);

    while (i <= j) {
        while (comp.get(i).compareTo(pivot)<0)
            i++;

        while (comp.get(i).compareTo(pivot)>0)
            j--;

        if (i <= j) {
            swap(comp, l2, i++, j--);
        }
    };
    return i;
}
private <T extends Comparable<? super T>>  void quickSort(List<T> comp, List<?> l2, int left, int right) {
    int index = partition(comp, l2, left, right);

    if (left < index - 1)
        quickSort(comp, l2, left, index - 1);

    if (index < right)
        quickSort(comp, l2, index, right);
}

public <T extends Comparable<? super T>>  void quickSort(List<T> comp, List<?> l2) {
    if (comp.size()<l2.size())
        throw new IndexOutOfBoundsException();
    quickSort(comp, l2, 0, comp.size());
}

【讨论】:

  • 这不起作用。例如。尝试使用列表 {1,2,3,4,5} 对列表 {"abc", "cde","egg", "high", "jkl"} 进行排序。这里 comp 将是 {1,2,3,4,5}。这不是无限循环。
【解决方案5】:

创建一个临时映射名称->编号,然后使用使用该映射的自定义比较器对名称进行排序:

Map<String, Integer> m = new HashMap<String, Integer>;
for(int i = 0; i < Names.size(); i++)
    m.put(Names.get(i), results.get(i));
Collections.sort(Names, new Comparator<String>() {
    @Override
    public int compare(String s1, s2) { return m.get(s2) - m.get(s1); }
});

即使某些数字相等,此解决方案也有效。

【讨论】:

  • 对此进行测试。我在行出现错误:“Names.sort(new Comparator() {”
  • 哎呀。如果我很好理解这个你的名字,对吗?但它用数字分别对它们进行排序,而不是根据它们的值。没有?
  • @FILIas 我忘记了 sort() 方法不在 List 上,现在应该可以工作了。 Comparator 使用之前的映射进行排序,降序也在这里。
  • 正确的miah。但是不同的价值观呢?你确定它真的适用于相同的值吗?导致通常哈希图不会
  • 这张地图是名称->编号,而不是其他方式。名字是独一无二的,对吧?
猜你喜欢
  • 2015-08-29
  • 2011-09-30
  • 2018-11-15
  • 1970-01-01
  • 2023-04-01
  • 2021-05-02
相关资源
最近更新 更多