【问题标题】:Which Map/Array-Datatype is most suitable for storing and sorting a value pair in Java?哪种 Map/Array-Datatype 最适合在 Java 中存储和排序值对?
【发布时间】:2021-05-02 10:46:15
【问题描述】:

在 Java 中,我有一个动态的(大小:例如 5-45)值对(double、int)列表。我想按第一个双值(不是唯一的!)对列表进行降序排序,并获得第二个 int 值的排序列表。

例如:

input:
0.245  3654
-0.12  7466
0.421  2551
-0.12  1882
0.637  3662
-0.35  5221
0.421  6332

sorted:
0.637  3662
0.421  2551
0.421  6332
0.245  3654
-0.12  7466
-0.12  1882
-0.35  5221

我想要一个普通的 ArrayList,例如:3662 2551 6332 3654 7466 1882 5221

是否有一些相同的双值并不重要;先到先得。

我不能使用排序的 TreeMap,因为第一个值 (double) 不是唯一的。其他 HashMaps/LinkedLists/ArrayLists/Arrays 呢? 我手动尝试(在一个循环中,比较所有值并保留 2 个列表),它有效,但速度很慢。我也尝试了 2d Array double[][] (但它们的长度必须是固定的,而且我在某处得到了一些空指针)。

我需要:高排序性能,并且 - 如果可能 - 不需要额外的框架(例如 MultiMap)在您看来最优雅和最快的方式是什么?

这是我自己的初学者风格(但这太慢了!!):

pair-value is: e m

for (...kind of a loop...){
    e = method.get(....);
    m = method.get(....);
                            if (eList.isEmpty()) {
                                eList.add(e);
                                rList.add(m);
                            } else {
                                higher = false;
                                for (int i = 0; i < eList.size(); i++) {
                                    if (e >= eList.get(i)) {
                                        eList.add(i, e);
                                        rList.add(i, m);
                                        higher = true;
                                        break;
                                    }
                                }
                                if (!higher) {
                                    eList.add(e);
                                    rList.add(m);
                                }
}

【问题讨论】:

  • 显示您的 HashMaps/LinkedLists/ArrayLists/Arrays 尝试,以便其他人可以看到并评估如何改进代码
  • 您真的需要对整个列表进行排序还是只对列表的一部分进行排序?该列表是否适合内存,还是必须从磁盘中流式传输?
  • 它基本上是一个值对列表,是吗?所以创建一个ValuePair 类并创建一个List&lt;ValuePair&gt; 来保存它们。按ValuePairdouble 成员降序排序并按int 成员升序排序?没问题!您可以创建一个 Comparatot&lt;ValueList&gt; 来强制执行您喜欢的任何排序顺序,并将其与 Collections.sort() 一起使用。
  • 是的,我需要对整个列表进行排序。并且最多条目约为 65,因此它应该很容易放入内存中。我的尝试真的是初学者的风格,发布很可惜。这只是一种解决方法,但我想有强大的数据类型(地图/列表),它们的内置排序算法应该性能更高。所以请告诉我,如果你有一些想法。
  • @KevinAnderson:是的,这可能是个好主意,我会考虑的。速度快吗?

标签: java arrays sorting dictionary arraylist


【解决方案1】:

非常感谢您提出的许多好的建议。我简单地尝试了所有这些,但我不得不说我的第一个算法实际上是最快的(我很惊讶可以在迭代列表时扩展它)。这是关于我自己编写的 JAVA 国际象棋程序,我对此感到非常自豪,我想根据个人着法的评分来排序一个着法列表。那么搜索应该会更快,或者你可以切断不重要的动作。 现在你明白了为什么我要找的这段代码必须这么快。由于递归和大深度,每一纳秒都被取幂。所以我可以测量到 TreeMap 慢了 30%:-o !! 与比较器相关的配对对象也慢了大约 35%。 因此我的问题又来了:我可以让我上面的方法(使用手动循环)更快吗?

【讨论】:

    【解决方案2】:

    您认为最优雅、最快捷的方式是什么?

    在我看来,最优雅和最快的方法是使用TreeMap&lt;Double, List&lt;Integer&gt;&gt;。这将是一个使用内置 Java 功能的multimap

    来自

    input:
    0.245  3654
    -0.12  7466
    0.421  2551
    -0.12  1882
    0.637  3662
    -0.35  5221
    0.421  6332
    

    你有TreeMap&lt;Double, List&lt;Integer&gt;&gt;

    0.637 = {3662}
    0.421 = {2551,6332}
    0.245 = {3654}
    -0.12 = {7466,1882}
    -0.35 = {5221}
    

    例如使用

      for (Pair<Integer, Double> pair : list) {
         Double score= pair.getValue();
         treeMap.putIfAbsent(score, new ArrayList<>());
         treeMap.get(score).add(pair.getKey());
      } 
    

    然后你可以迭代并生成普通的ArrayList,例如:{3662 2551 6332 3654 7466 1882 5221},例如

    List<Integer> result = new ArrayList<>();
    for (List<Integer> list : map.values()) {
        result.addAll(list);
    } 
    

    【讨论】:

    • 谢谢 - 这可能也是一个想法。看起来不错。你能否告诉我,如何将值对放入 TreeMap。我怎样才能以最简单的方式在最后迭代它?
    • 是的,但是如何填充 TreeMap? treeMap.put(0.245,3654) 不起作用,因为 arrayList 是预期的!
    • 我补充一下如何填写
    • 谢谢!它似乎有效..但反之亦然....从-0.35到0.637 ...我可以改变那个somhow吗?
    • 啊!我发现: TreeMap> tm = new TreeMap>(Collections.reverseOrder());然后它以正确的方式排序。但是这个机制非常非常慢!!! :-(
    【解决方案3】:

    另一种方法是创建一个包含doubleint 值的Pair

         class Pair {
            private Double doubleVal;
            private Integer intVal;
    
            public Pair(Double doubleVal, Integer intVal) {
                this.doubleVal = doubleVal;
                this.intVal = intVal;
            }
    
            public double getDoubleVal() {
                return doubleVal;
            }
    
            public int getIntVal() {
                return intVal;
            }
        }
    

    并在List&lt;Pair&gt; 中收集输入

    List<Pair> pairs = Arrays
                .asList(new Pair(0.245, 3654), new Pair(-0.12, 7466), /*further elements*/);
    

    现在,Collections.sort() 可以通过提供所需的Comparator 来使用,例如:

    Collections.sort(pairs, Comparator.comparingDouble(Pair::getDoubleVal).reversed());
    

    这将根据double 值按降序对pairs 集合进行排序。就排序性能而言,Collections.sort() 使用Tim Sort(我正在运行 zulu JDK8。因此默认使用此排序算法)在最坏的情况下以O(nlogn) 运行。

    这样,可以得到一个像{3662 2551 6332 3654 7466 1882 5221}这样的普通数组列表

    pairs.stream().map(Pair::getIntVal).collect(Collectors.toList())
    

    【讨论】:

    • 谢谢 - 这也有效。但它比我第一次尝试慢得多(见我的问题):-(
    猜你喜欢
    • 2011-10-15
    • 2019-09-05
    • 2010-11-15
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    相关资源
    最近更新 更多